From c18baaeb7b68df22f8db5ee6c571b14731852588 Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Fri, 21 Apr 2023 10:15:51 +0300 Subject: [PATCH 01/31] some hepler things like artifactory, fs and http --- package.json | 1 + pnpm-lock.yaml | 1019 +++++++++++++++++++++++++++++++++++++++ src/artifactory.mts | 89 ++++ src/cli.mts | 8 +- src/config.mts | 5 +- src/deb/deb-builder.mts | 24 + src/deb/deb-config.mts | 4 + src/fs.mts | 19 + src/http.mts | 91 ++++ src/ibuilder.mts | 6 + src/index.mts | 8 +- 11 files changed, 1267 insertions(+), 7 deletions(-) create mode 100644 src/artifactory.mts create mode 100644 src/deb/deb-builder.mts create mode 100644 src/deb/deb-config.mts create mode 100644 src/fs.mts create mode 100644 src/http.mts create mode 100644 src/ibuilder.mts diff --git a/package.json b/package.json index 647ac4b..c856cdb 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "husky": "^8.0.0", "jest": "^29.3.1", "lint-staged": "^13.0.4", + "s3-groundskeeper": "0.2.2", "ts-jest": "^29.1.0", "ts-node": "^10.9.1", "typescript": "^5.0.4" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0dfd696..a0eeaa5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,7 @@ importers: husky: ^8.0.0 jest: ^29.3.1 lint-staged: ^13.0.4 + s3-groundskeeper: 0.2.2 ts-jest: ^29.1.0 ts-node: ^10.9.1 typescript: ^5.0.4 @@ -37,6 +38,7 @@ importers: husky: 8.0.2 jest: 29.3.1_qypvtqa6r6yb6tpkajpqa7nibu lint-staged: 13.0.4 + s3-groundskeeper: 0.2.2 ts-jest: 29.1.0_agn56dcmrvrjxyb3wli3ryy5gy ts-node: 10.9.1_prmsu5cq6ukh7eypgb4uwwpoa4 typescript: 5.0.4 @@ -57,6 +59,955 @@ packages: '@jridgewell/trace-mapping': 0.3.17 dev: true + /@aws-crypto/crc32/3.0.0: + resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==} + dependencies: + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.310.0 + tslib: 1.14.1 + dev: true + + /@aws-crypto/crc32c/3.0.0: + resolution: {integrity: sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==} + dependencies: + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.310.0 + tslib: 1.14.1 + dev: true + + /@aws-crypto/ie11-detection/3.0.0: + resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==} + dependencies: + tslib: 1.14.1 + dev: true + + /@aws-crypto/sha1-browser/3.0.0: + resolution: {integrity: sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==} + dependencies: + '@aws-crypto/ie11-detection': 3.0.0 + '@aws-crypto/supports-web-crypto': 3.0.0 + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-locate-window': 3.310.0 + '@aws-sdk/util-utf8-browser': 3.259.0 + tslib: 1.14.1 + dev: true + + /@aws-crypto/sha256-browser/3.0.0: + resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==} + dependencies: + '@aws-crypto/ie11-detection': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-crypto/supports-web-crypto': 3.0.0 + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-locate-window': 3.310.0 + '@aws-sdk/util-utf8-browser': 3.259.0 + tslib: 1.14.1 + dev: true + + /@aws-crypto/sha256-js/3.0.0: + resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} + dependencies: + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.310.0 + tslib: 1.14.1 + dev: true + + /@aws-crypto/supports-web-crypto/3.0.0: + resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} + dependencies: + tslib: 1.14.1 + dev: true + + /@aws-crypto/util/3.0.0: + resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} + dependencies: + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-utf8-browser': 3.259.0 + tslib: 1.14.1 + dev: true + + /@aws-sdk/abort-controller/3.310.0: + resolution: {integrity: sha512-v1zrRQxDLA1MdPim159Vx/CPHqsB4uybSxRi1CnfHO5ZjHryx3a5htW2gdGAykVCul40+yJXvfpufMrELVxH+g==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/chunked-blob-reader/3.310.0: + resolution: {integrity: sha512-CrJS3exo4mWaLnWxfCH+w88Ou0IcAZSIkk4QbmxiHl/5Dq705OLoxf4385MVyExpqpeVJYOYQ2WaD8i/pQZ2fg==} + dependencies: + tslib: 2.5.0 + dev: true + + /@aws-sdk/client-s3/3.315.0: + resolution: {integrity: sha512-sE2pCFNrhkn1XdqkHx1GEd4eKg/kITk2zHETpkQCUMAVZ1MDuY/uUZzRjbAn9sm9EsJ03Z/vOuK4DkxlLFY+8g==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha1-browser': 3.0.0 + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.315.0 + '@aws-sdk/config-resolver': 3.310.0 + '@aws-sdk/credential-provider-node': 3.315.0 + '@aws-sdk/eventstream-serde-browser': 3.310.0 + '@aws-sdk/eventstream-serde-config-resolver': 3.310.0 + '@aws-sdk/eventstream-serde-node': 3.310.0 + '@aws-sdk/fetch-http-handler': 3.310.0 + '@aws-sdk/hash-blob-browser': 3.310.0 + '@aws-sdk/hash-node': 3.310.0 + '@aws-sdk/hash-stream-node': 3.310.0 + '@aws-sdk/invalid-dependency': 3.310.0 + '@aws-sdk/md5-js': 3.310.0 + '@aws-sdk/middleware-bucket-endpoint': 3.310.0 + '@aws-sdk/middleware-content-length': 3.310.0 + '@aws-sdk/middleware-endpoint': 3.310.0 + '@aws-sdk/middleware-expect-continue': 3.310.0 + '@aws-sdk/middleware-flexible-checksums': 3.310.0 + '@aws-sdk/middleware-host-header': 3.310.0 + '@aws-sdk/middleware-location-constraint': 3.310.0 + '@aws-sdk/middleware-logger': 3.310.0 + '@aws-sdk/middleware-recursion-detection': 3.310.0 + '@aws-sdk/middleware-retry': 3.310.0 + '@aws-sdk/middleware-sdk-s3': 3.310.0 + '@aws-sdk/middleware-serde': 3.310.0 + '@aws-sdk/middleware-signing': 3.310.0 + '@aws-sdk/middleware-ssec': 3.310.0 + '@aws-sdk/middleware-stack': 3.310.0 + '@aws-sdk/middleware-user-agent': 3.310.0 + '@aws-sdk/node-config-provider': 3.310.0 + '@aws-sdk/node-http-handler': 3.310.0 + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/signature-v4-multi-region': 3.310.0 + '@aws-sdk/smithy-client': 3.315.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/url-parser': 3.310.0 + '@aws-sdk/util-base64': 3.310.0 + '@aws-sdk/util-body-length-browser': 3.310.0 + '@aws-sdk/util-body-length-node': 3.310.0 + '@aws-sdk/util-defaults-mode-browser': 3.315.0 + '@aws-sdk/util-defaults-mode-node': 3.315.0 + '@aws-sdk/util-endpoints': 3.310.0 + '@aws-sdk/util-retry': 3.310.0 + '@aws-sdk/util-stream-browser': 3.310.0 + '@aws-sdk/util-stream-node': 3.310.0 + '@aws-sdk/util-user-agent-browser': 3.310.0 + '@aws-sdk/util-user-agent-node': 3.310.0 + '@aws-sdk/util-utf8': 3.310.0 + '@aws-sdk/util-waiter': 3.310.0 + '@aws-sdk/xml-builder': 3.310.0 + fast-xml-parser: 4.1.2 + tslib: 2.5.0 + transitivePeerDependencies: + - '@aws-sdk/signature-v4-crt' + - aws-crt + dev: true + + /@aws-sdk/client-sso-oidc/3.315.0: + resolution: {integrity: sha512-OJgtmx6SpCWHBDCxBBi36Ro44uCqZBufGkThP/PVYrgVnRVnJ4V18d2wNGKmS37zKmCHHJPnhMPlGOgE2qyVPQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/config-resolver': 3.310.0 + '@aws-sdk/fetch-http-handler': 3.310.0 + '@aws-sdk/hash-node': 3.310.0 + '@aws-sdk/invalid-dependency': 3.310.0 + '@aws-sdk/middleware-content-length': 3.310.0 + '@aws-sdk/middleware-endpoint': 3.310.0 + '@aws-sdk/middleware-host-header': 3.310.0 + '@aws-sdk/middleware-logger': 3.310.0 + '@aws-sdk/middleware-recursion-detection': 3.310.0 + '@aws-sdk/middleware-retry': 3.310.0 + '@aws-sdk/middleware-serde': 3.310.0 + '@aws-sdk/middleware-stack': 3.310.0 + '@aws-sdk/middleware-user-agent': 3.310.0 + '@aws-sdk/node-config-provider': 3.310.0 + '@aws-sdk/node-http-handler': 3.310.0 + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/smithy-client': 3.315.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/url-parser': 3.310.0 + '@aws-sdk/util-base64': 3.310.0 + '@aws-sdk/util-body-length-browser': 3.310.0 + '@aws-sdk/util-body-length-node': 3.310.0 + '@aws-sdk/util-defaults-mode-browser': 3.315.0 + '@aws-sdk/util-defaults-mode-node': 3.315.0 + '@aws-sdk/util-endpoints': 3.310.0 + '@aws-sdk/util-retry': 3.310.0 + '@aws-sdk/util-user-agent-browser': 3.310.0 + '@aws-sdk/util-user-agent-node': 3.310.0 + '@aws-sdk/util-utf8': 3.310.0 + tslib: 2.5.0 + transitivePeerDependencies: + - aws-crt + dev: true + + /@aws-sdk/client-sso/3.315.0: + resolution: {integrity: sha512-P3QOOyHQER7EDVCzXOsAaJE2p/qfdsSFsYv8k2S8LqEKGH0fViQ4Ph540uKlmaOt1kEhwH1wI6cLRMJJX9XV4Q==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/config-resolver': 3.310.0 + '@aws-sdk/fetch-http-handler': 3.310.0 + '@aws-sdk/hash-node': 3.310.0 + '@aws-sdk/invalid-dependency': 3.310.0 + '@aws-sdk/middleware-content-length': 3.310.0 + '@aws-sdk/middleware-endpoint': 3.310.0 + '@aws-sdk/middleware-host-header': 3.310.0 + '@aws-sdk/middleware-logger': 3.310.0 + '@aws-sdk/middleware-recursion-detection': 3.310.0 + '@aws-sdk/middleware-retry': 3.310.0 + '@aws-sdk/middleware-serde': 3.310.0 + '@aws-sdk/middleware-stack': 3.310.0 + '@aws-sdk/middleware-user-agent': 3.310.0 + '@aws-sdk/node-config-provider': 3.310.0 + '@aws-sdk/node-http-handler': 3.310.0 + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/smithy-client': 3.315.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/url-parser': 3.310.0 + '@aws-sdk/util-base64': 3.310.0 + '@aws-sdk/util-body-length-browser': 3.310.0 + '@aws-sdk/util-body-length-node': 3.310.0 + '@aws-sdk/util-defaults-mode-browser': 3.315.0 + '@aws-sdk/util-defaults-mode-node': 3.315.0 + '@aws-sdk/util-endpoints': 3.310.0 + '@aws-sdk/util-retry': 3.310.0 + '@aws-sdk/util-user-agent-browser': 3.310.0 + '@aws-sdk/util-user-agent-node': 3.310.0 + '@aws-sdk/util-utf8': 3.310.0 + tslib: 2.5.0 + transitivePeerDependencies: + - aws-crt + dev: true + + /@aws-sdk/client-sts/3.315.0: + resolution: {integrity: sha512-e34plg6m0hScADIPiu5kCKoiJVXRLRiAuens+iwMse0oPUmrv41hdjgufwWGA/pcNkEGzMdVS88Z4khxB3LHBw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/config-resolver': 3.310.0 + '@aws-sdk/credential-provider-node': 3.315.0 + '@aws-sdk/fetch-http-handler': 3.310.0 + '@aws-sdk/hash-node': 3.310.0 + '@aws-sdk/invalid-dependency': 3.310.0 + '@aws-sdk/middleware-content-length': 3.310.0 + '@aws-sdk/middleware-endpoint': 3.310.0 + '@aws-sdk/middleware-host-header': 3.310.0 + '@aws-sdk/middleware-logger': 3.310.0 + '@aws-sdk/middleware-recursion-detection': 3.310.0 + '@aws-sdk/middleware-retry': 3.310.0 + '@aws-sdk/middleware-sdk-sts': 3.310.0 + '@aws-sdk/middleware-serde': 3.310.0 + '@aws-sdk/middleware-signing': 3.310.0 + '@aws-sdk/middleware-stack': 3.310.0 + '@aws-sdk/middleware-user-agent': 3.310.0 + '@aws-sdk/node-config-provider': 3.310.0 + '@aws-sdk/node-http-handler': 3.310.0 + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/smithy-client': 3.315.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/url-parser': 3.310.0 + '@aws-sdk/util-base64': 3.310.0 + '@aws-sdk/util-body-length-browser': 3.310.0 + '@aws-sdk/util-body-length-node': 3.310.0 + '@aws-sdk/util-defaults-mode-browser': 3.315.0 + '@aws-sdk/util-defaults-mode-node': 3.315.0 + '@aws-sdk/util-endpoints': 3.310.0 + '@aws-sdk/util-retry': 3.310.0 + '@aws-sdk/util-user-agent-browser': 3.310.0 + '@aws-sdk/util-user-agent-node': 3.310.0 + '@aws-sdk/util-utf8': 3.310.0 + fast-xml-parser: 4.1.2 + tslib: 2.5.0 + transitivePeerDependencies: + - aws-crt + dev: true + + /@aws-sdk/config-resolver/3.310.0: + resolution: {integrity: sha512-8vsT+/50lOqfDxka9m/rRt6oxv1WuGZoP8oPMk0Dt+TxXMbAzf4+rejBgiB96wshI1k3gLokYRjSQZn+dDtT8g==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-config-provider': 3.310.0 + '@aws-sdk/util-middleware': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/credential-provider-env/3.310.0: + resolution: {integrity: sha512-vvIPQpI16fj95xwS7M3D48F7QhZJBnnCgB5lR+b7So+vsG9ibm1mZRVGzVpdxCvgyOhHFbvrby9aalNJmmIP1A==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/credential-provider-imds/3.310.0: + resolution: {integrity: sha512-baxK7Zp6dai5AGW01FIW27xS2KAaPUmKLIXv5SvFYsUgXXvNW55im4uG3b+2gA0F7V+hXvVBH08OEqmwW6we5w==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/node-config-provider': 3.310.0 + '@aws-sdk/property-provider': 3.310.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/url-parser': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/credential-provider-ini/3.315.0: + resolution: {integrity: sha512-TZbYNbQkNgANx3KsWmJEyBsnfUBq/XKqYYc/VQf1L4eI+GMUw2eKpNV0MTsyviViy2st7W4SiSgtsvXyeVp9xg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/credential-provider-env': 3.310.0 + '@aws-sdk/credential-provider-imds': 3.310.0 + '@aws-sdk/credential-provider-process': 3.310.0 + '@aws-sdk/credential-provider-sso': 3.315.0 + '@aws-sdk/credential-provider-web-identity': 3.310.0 + '@aws-sdk/property-provider': 3.310.0 + '@aws-sdk/shared-ini-file-loader': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + transitivePeerDependencies: + - aws-crt + dev: true + + /@aws-sdk/credential-provider-node/3.315.0: + resolution: {integrity: sha512-OuzKAIg+xPAzBrb/Big5VKDpJmBhVR+N0Hfflrjj2BunQGWO7zxtkKFCz921MtP9ZunDV+UxzTpar8U5TAPtzA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/credential-provider-env': 3.310.0 + '@aws-sdk/credential-provider-imds': 3.310.0 + '@aws-sdk/credential-provider-ini': 3.315.0 + '@aws-sdk/credential-provider-process': 3.310.0 + '@aws-sdk/credential-provider-sso': 3.315.0 + '@aws-sdk/credential-provider-web-identity': 3.310.0 + '@aws-sdk/property-provider': 3.310.0 + '@aws-sdk/shared-ini-file-loader': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + transitivePeerDependencies: + - aws-crt + dev: true + + /@aws-sdk/credential-provider-process/3.310.0: + resolution: {integrity: sha512-h73sg6GPMUWC+3zMCbA1nZ2O03nNJt7G96JdmnantiXBwHpRKWW8nBTLzx5uhXn6hTuTaoQRP/P+oxQJKYdMmA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.310.0 + '@aws-sdk/shared-ini-file-loader': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/credential-provider-sso/3.315.0: + resolution: {integrity: sha512-oMDGwT67cLgLiLEj5UwAiOVo7mb0l4vi2nk+5pgPMpC3cBlAfA0y1IJe4FHp+Vz52F0nvURZZbdWhX6RgMMaqQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-sso': 3.315.0 + '@aws-sdk/property-provider': 3.310.0 + '@aws-sdk/shared-ini-file-loader': 3.310.0 + '@aws-sdk/token-providers': 3.315.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + transitivePeerDependencies: + - aws-crt + dev: true + + /@aws-sdk/credential-provider-web-identity/3.310.0: + resolution: {integrity: sha512-H4SzuZXILNhK6/IR1uVvsUDZvzc051hem7GLyYghBCu8mU+tq28YhKE8MfSroi6eL2e5Vujloij1OM2EQQkPkw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/eventstream-codec/3.310.0: + resolution: {integrity: sha512-clIeSgWbZbxwtsxZ/yoedNM0/kJFSIjjHPikuDGhxhqc+vP6TN3oYyVMFrYwFaTFhk2+S5wZcWYMw8Op1pWo+A==} + dependencies: + '@aws-crypto/crc32': 3.0.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-hex-encoding': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/eventstream-serde-browser/3.310.0: + resolution: {integrity: sha512-3S6ziuQVALgEyz0TANGtYDVeG8ArK4Y05mcgrs8qUTmsvlDIXX37cR/DvmVbNB76M4IrsZeSAIajL9644CywkA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/eventstream-serde-universal': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/eventstream-serde-config-resolver/3.310.0: + resolution: {integrity: sha512-8s1Qdn9STj+sV75nUp9yt0W6fHS4BZ2jTm4Z/1Pcbvh2Gqs0WjH5n2StS+pDW5Y9J/HSGBl0ogmUr5lC5bXFHg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/eventstream-serde-node/3.310.0: + resolution: {integrity: sha512-kSnRomCgW43K9TmQYuwN9+AoYPnhyOKroanUMyZEzJk7rpCPMj4OzaUpXfDYOvznFNYn7NLaH6nHLJAr0VPlJA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/eventstream-serde-universal': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/eventstream-serde-universal/3.310.0: + resolution: {integrity: sha512-Qyjt5k/waV5cDukpgT824ISZAz5U0pwzLz5ztR409u85AGNkF/9n7MS+LSyBUBSb0WJ5pUeSD47WBk+nLq9Nhw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/eventstream-codec': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/fetch-http-handler/3.310.0: + resolution: {integrity: sha512-Bi9vIwzdkw1zMcvi/zGzlWS9KfIEnAq4NNhsnCxbQ4OoIRU9wvU+WGZdBBhxg0ZxZmpp1j1aZhU53lLjA07MHw==} + dependencies: + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/querystring-builder': 3.310.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-base64': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/hash-blob-browser/3.310.0: + resolution: {integrity: sha512-OoR8p0cbypToysLT0v3o2oyjy6+DKrY7GNCAzHOHJK9xmqXCt+DsjKoPeiY7o1sWX2aN6Plmvubj/zWxMKEn/A==} + dependencies: + '@aws-sdk/chunked-blob-reader': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/hash-node/3.310.0: + resolution: {integrity: sha512-NvE2fhRc8GRwCXBfDehxVAWCmVwVMILliAKVPAEr4yz2CkYs0tqU51S48x23dtna07H4qHtgpeNqVTthcIQOEQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-buffer-from': 3.310.0 + '@aws-sdk/util-utf8': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/hash-stream-node/3.310.0: + resolution: {integrity: sha512-ZoXdybNgvMz1Hl6k/e32xVL3jmG5p2IEk5mTtLfFEuskTJ74Z+VMYKkkF1whyy7KQfH83H+TQGnsGtlRCchQKw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-utf8': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/invalid-dependency/3.310.0: + resolution: {integrity: sha512-1s5RG5rSPXoa/aZ/Kqr5U/7lqpx+Ry81GprQ2bxWqJvWQIJ0IRUwo5pk8XFxbKVr/2a+4lZT/c3OGoBOM1yRRA==} + dependencies: + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/is-array-buffer/3.310.0: + resolution: {integrity: sha512-urnbcCR+h9NWUnmOtet/s4ghvzsidFmspfhYaHAmSRdy9yDjdjBJMFjjsn85A1ODUktztm+cVncXjQ38WCMjMQ==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.5.0 + dev: true + + /@aws-sdk/md5-js/3.310.0: + resolution: {integrity: sha512-x5sRBUrEfLWAS1EhwbbDQ7cXq6uvBxh3qR2XAsnGvFFceTeAadk7cVogWxlk3PC+OCeeym7c3/6Bv2HQ2f1YyQ==} + dependencies: + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-utf8': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-bucket-endpoint/3.310.0: + resolution: {integrity: sha512-uJJfHI7v4AgbJZRLtyI8ap2QRWkBokGc3iyUoQ+dVNT3/CE2ZCu694A6W+H0dRqg79dIE+f9CRNdtLGa/Ehhvg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-arn-parser': 3.310.0 + '@aws-sdk/util-config-provider': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-content-length/3.310.0: + resolution: {integrity: sha512-P8tQZxgDt6CAh1wd/W6WPzjc+uWPJwQkm+F7rAwRlM+k9q17HrhnksGDKcpuuLyIhPQYdmOMIkpKVgXGa4avhQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-endpoint/3.310.0: + resolution: {integrity: sha512-Z+N2vOL8K354/lstkClxLLsr6hCpVRh+0tCMXrVj66/NtKysCEZ/0b9LmqOwD9pWHNiI2mJqXwY0gxNlKAroUg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/middleware-serde': 3.310.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/url-parser': 3.310.0 + '@aws-sdk/util-middleware': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-expect-continue/3.310.0: + resolution: {integrity: sha512-l3d1z2gt+gINJDnPSyu84IxfzjzPfCQrqC1sunw2cZGo/sXtEiq698Q3SiTcO2PGP4LBQAy2RHb5wVBJP708CQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-flexible-checksums/3.310.0: + resolution: {integrity: sha512-5ndnLgzgGVpWkmHBAiYkagHqiSuow8q62J4J6E2PzaQ77+fm8W3nfdy7hK5trHokEyouCZdxT/XK/IRhgj/4PA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/crc32': 3.0.0 + '@aws-crypto/crc32c': 3.0.0 + '@aws-sdk/is-array-buffer': 3.310.0 + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-utf8': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-host-header/3.310.0: + resolution: {integrity: sha512-QWSA+46/hXorXyWa61ic2K7qZzwHTiwfk2e9mRRjeIRepUgI3qxFjsYqrWtrOGBjmFmq0pYIY8Bb/DCJuQqcoA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-location-constraint/3.310.0: + resolution: {integrity: sha512-LFm0JTQWwTPWL/tZU2wsQTl8J5PpDEkXjEhaXVKamtyH0xhysRqd+0n92n65dc8oztAuQkb9xUbErGn5b6gsew==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-logger/3.310.0: + resolution: {integrity: sha512-Lurm8XofrASBRnAVtiSNuDSRsRqPNg27RIFLLsLp/pqog9nFJ0vz0kgdb9S5Z+zw83Mm+UlqOe6D8NTUNp4fVg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-recursion-detection/3.310.0: + resolution: {integrity: sha512-SuB75/xk/gyue24gkriTwO2jFd7YcUGZDClQYuRejgbXSa3CO0lWyawQtfLcSSEBp9izrEVXuFH24K1eAft5nQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-retry/3.310.0: + resolution: {integrity: sha512-oTPsRy2W4s+dfxbJPW7Km+hHtv/OMsNsVfThAq8DDYKC13qlr1aAyOqGLD+dpBy2aKe7ss517Sy2HcHtHqm7/g==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/service-error-classification': 3.310.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-middleware': 3.310.0 + '@aws-sdk/util-retry': 3.310.0 + tslib: 2.5.0 + uuid: 8.3.2 + dev: true + + /@aws-sdk/middleware-sdk-s3/3.310.0: + resolution: {integrity: sha512-QK9x9g2ksg0hOjjYgqddeFcn5ctUEGdxJVu4OumPXceulefMcSO2jyH2qTybYSA93nqNQFdFmg5wQfvIRUWFCQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-arn-parser': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-sdk-sts/3.310.0: + resolution: {integrity: sha512-+5PFwlYNLvLLIfw0ASAoWV/iIF8Zv6R6QGtyP0CclhRSvNjgbQDVnV0g95MC5qvh+GB/Yjlkt8qAjLSPjHfsrQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/middleware-signing': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-serde/3.310.0: + resolution: {integrity: sha512-RNeeTVWSLTaentUeCgQKZhAl+C6hxtwD78cQWS10UymWpQFwbaxztzKUu4UQS5xA2j6PxwPRRUjqa4jcFjfLsg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-signing/3.310.0: + resolution: {integrity: sha512-f9mKq+XMdW207Af3hKjdTnpNhdtwqWuvFs/ZyXoOkp/g1MY1O6L23Jy6i52m29LxbT4AuNRG1oKODfXM0vYVjQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.310.0 + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/signature-v4': 3.310.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-middleware': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-ssec/3.310.0: + resolution: {integrity: sha512-CnEwNKVpd5bXnrCKPaePF8mWTA9ET21OMBb54y9b0fd8K02zoOcdBz4DWfh1SjFD4HkgCdja4egd8l2ivyvqmw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-stack/3.310.0: + resolution: {integrity: sha512-010O1PD+UAcZVKRvqEusE1KJqN96wwrf6QsqbRM0ywsKQ21NDweaHvEDlds2VHpgmofxkRLRu/IDrlPkKRQrRg==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.5.0 + dev: true + + /@aws-sdk/middleware-user-agent/3.310.0: + resolution: {integrity: sha512-x3IOwSwSbwKidlxRk3CNVHVUb06SRuaELxggCaR++QVI8NU6qD/l4VHXKVRvbTHiC/cYxXE/GaBDgQVpDR7V/g==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-endpoints': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/node-config-provider/3.310.0: + resolution: {integrity: sha512-T/Pp6htc6hq/Cq+MLNDSyiwWCMVF6GqbBbXKVlO5L8rdHx4sq9xPdoPveZhGWrxvkanjA6eCwUp6E0riBOSVng==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.310.0 + '@aws-sdk/shared-ini-file-loader': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/node-http-handler/3.310.0: + resolution: {integrity: sha512-irv9mbcM9xC2xYjArQF5SYmHBMu4ciMWtGsoHII1nRuFOl9FoT4ffTvEPuLlfC6pznzvKt9zvnm6xXj7gDChKg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/abort-controller': 3.310.0 + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/querystring-builder': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/property-provider/3.310.0: + resolution: {integrity: sha512-3lxDb0akV6BBzmFe4nLPaoliQbAifyWJhuvuDOu7e8NzouvpQXs0275w9LePhhcgjKAEVXUIse05ZW2DLbxo/g==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/protocol-http/3.310.0: + resolution: {integrity: sha512-fgZ1aw/irQtnrsR58pS8ThKOWo57Py3xX6giRvwSgZDEcxHfVzuQjy9yPuV++v04fdmdtgpbGf8WfvAAJ11yXQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/querystring-builder/3.310.0: + resolution: {integrity: sha512-ZHH8GV/80+pWGo7DzsvwvXR5xVxUHXUvPJPFAkhr6nCf78igdoF8gR10ScFoEKbtEapoNTaZlKHPXxpD8aPG7A==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-uri-escape': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/querystring-parser/3.310.0: + resolution: {integrity: sha512-YkIznoP6lsiIUHinx++/lbb3tlMURGGqMpo0Pnn32zYzGrJXA6eC3D0as2EcMjo55onTfuLcIiX4qzXes2MYOA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/service-error-classification/3.310.0: + resolution: {integrity: sha512-PuyC7k3qfIKeH2LCnDwbttMOKq3qAx4buvg0yfnJtQOz6t1AR8gsnAq0CjKXXyfkXwNKWTqCpE6lVNUIkXgsMw==} + engines: {node: '>=14.0.0'} + dev: true + + /@aws-sdk/shared-ini-file-loader/3.310.0: + resolution: {integrity: sha512-N0q9pG0xSjQwc690YQND5bofm+4nfUviQ/Ppgan2kU6aU0WUq8KwgHJBto/YEEI+VlrME30jZJnxtOvcZJc2XA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/signature-v4-multi-region/3.310.0: + resolution: {integrity: sha512-q8W+RIomTS/q85Ntgks/CoDElwqkC9+4OCicee5YznNHjQ4gtNWhUkYIyIRWRmXa/qx/AUreW9DM8FAecCOdng==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@aws-sdk/signature-v4-crt': ^3.118.0 + peerDependenciesMeta: + '@aws-sdk/signature-v4-crt': + optional: true + dependencies: + '@aws-sdk/protocol-http': 3.310.0 + '@aws-sdk/signature-v4': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/signature-v4/3.310.0: + resolution: {integrity: sha512-1M60P1ZBNAjCFv9sYW29OF6okktaeibWyW3lMXqzoHF70lHBZh+838iUchznXUA5FLabfn4jBFWMRxlAXJUY2Q==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/is-array-buffer': 3.310.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-hex-encoding': 3.310.0 + '@aws-sdk/util-middleware': 3.310.0 + '@aws-sdk/util-uri-escape': 3.310.0 + '@aws-sdk/util-utf8': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/smithy-client/3.315.0: + resolution: {integrity: sha512-qTm0lwTh6IZMiWs3U9k2veoF6gV9yE0B9Z34yMxagOfQFQgxMih0aiH25MD25eRigjJ3sfUeZ+B0mRycmJZdkQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/middleware-stack': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/token-providers/3.315.0: + resolution: {integrity: sha512-EjLUQ9JLqU3eJfJyzpcVjFnuJ1MCCodZaVJmuX/a/as4TK41bKMvkVojjsU7pDSYzl+tuXE+ceivcWK4H0HQdQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-sso-oidc': 3.315.0 + '@aws-sdk/property-provider': 3.310.0 + '@aws-sdk/shared-ini-file-loader': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + transitivePeerDependencies: + - aws-crt + dev: true + + /@aws-sdk/types/3.310.0: + resolution: {integrity: sha512-j8eamQJ7YcIhw7fneUfs8LYl3t01k4uHi4ZDmNRgtbmbmTTG3FZc2MotStZnp3nZB6vLiPF1o5aoJxWVvkzS6A==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.5.0 + dev: true + + /@aws-sdk/url-parser/3.310.0: + resolution: {integrity: sha512-mCLnCaSB9rQvAgx33u0DujLvr4d5yEm/W5r789GblwwQnlNXedVu50QRizMLTpltYWyAUoXjJgQnJHmJMaKXhw==} + dependencies: + '@aws-sdk/querystring-parser': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-arn-parser/3.310.0: + resolution: {integrity: sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-base64/3.310.0: + resolution: {integrity: sha512-v3+HBKQvqgdzcbL+pFswlx5HQsd9L6ZTlyPVL2LS9nNXnCcR3XgGz9jRskikRUuUvUXtkSG1J88GAOnJ/apTPg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/util-buffer-from': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-body-length-browser/3.310.0: + resolution: {integrity: sha512-sxsC3lPBGfpHtNTUoGXMQXLwjmR0zVpx0rSvzTPAuoVILVsp5AU/w5FphNPxD5OVIjNbZv9KsKTuvNTiZjDp9g==} + dependencies: + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-body-length-node/3.310.0: + resolution: {integrity: sha512-2tqGXdyKhyA6w4zz7UPoS8Ip+7sayOg9BwHNidiGm2ikbDxm1YrCfYXvCBdwaJxa4hJfRVz+aL9e+d3GqPI9pQ==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-buffer-from/3.310.0: + resolution: {integrity: sha512-i6LVeXFtGih5Zs8enLrt+ExXY92QV25jtEnTKHsmlFqFAuL3VBeod6boeMXkN2p9lbSVVQ1sAOOYZOHYbYkntw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/is-array-buffer': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-config-provider/3.310.0: + resolution: {integrity: sha512-xIBaYo8dwiojCw8vnUcIL4Z5tyfb1v3yjqyJKJWV/dqKUFOOS0U591plmXbM+M/QkXyML3ypon1f8+BoaDExrg==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-defaults-mode-browser/3.315.0: + resolution: {integrity: sha512-5cqNvfGos3FB/MHNl+g2fr+tPY7s3k3+96V3wOPWLOksdACth10OxPpHfboXXZDHHkR0hmyJwJcfgA4uQrUcGg==} + engines: {node: '>= 10.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.310.0 + '@aws-sdk/types': 3.310.0 + bowser: 2.11.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-defaults-mode-node/3.315.0: + resolution: {integrity: sha512-vSPIGpzh6NJIMLoh31p7CczSatN46kJdJBrHfODHaIGe4t156x+LfkkcxGQhtifqxglhL7l+fmn5D1fM5exHuA==} + engines: {node: '>= 10.0.0'} + dependencies: + '@aws-sdk/config-resolver': 3.310.0 + '@aws-sdk/credential-provider-imds': 3.310.0 + '@aws-sdk/node-config-provider': 3.310.0 + '@aws-sdk/property-provider': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-endpoints/3.310.0: + resolution: {integrity: sha512-zG+/d/O5KPmAaeOMPd6bW1abifdT0H03f42keLjYEoRZzYtHPC5DuPE0UayiWGckI6BCDgy0sRKXCYS49UNFaQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-hex-encoding/3.310.0: + resolution: {integrity: sha512-sVN7mcCCDSJ67pI1ZMtk84SKGqyix6/0A1Ab163YKn+lFBQRMKexleZzpYzNGxYzmQS6VanP/cfU7NiLQOaSfA==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-locate-window/3.310.0: + resolution: {integrity: sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-middleware/3.310.0: + resolution: {integrity: sha512-FTSUKL/eRb9X6uEZClrTe27QFXUNNp7fxYrPndZwk1hlaOP5ix+MIHBcI7pIiiY/JPfOUmPyZOu+HetlFXjWog==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-retry/3.310.0: + resolution: {integrity: sha512-FwWGhCBLfoivTMUHu1LIn4NjrN9JLJ/aX5aZmbcPIOhZVFJj638j0qDgZXyfvVqBuBZh7M8kGq0Oahy3dp69OA==} + engines: {node: '>= 14.0.0'} + dependencies: + '@aws-sdk/service-error-classification': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-stream-browser/3.310.0: + resolution: {integrity: sha512-bysXZHwFwvbqOTCScCdCnoLk1K3GCo0HRIYEZuL7O7MHrQmfaYRXcaft/p22+GUv9VeFXS/eJJZ5r4u32az94w==} + dependencies: + '@aws-sdk/fetch-http-handler': 3.310.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-base64': 3.310.0 + '@aws-sdk/util-hex-encoding': 3.310.0 + '@aws-sdk/util-utf8': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-stream-node/3.310.0: + resolution: {integrity: sha512-hueAXFK0GVvnfYFgqbF7587xZfMZff5jlIFZOHqx7XVU7bl7qrRUCnphHk8H6yZ7RoQbDPcfmHJgtEoAJg1T1Q==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/node-http-handler': 3.310.0 + '@aws-sdk/types': 3.310.0 + '@aws-sdk/util-buffer-from': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-uri-escape/3.310.0: + resolution: {integrity: sha512-drzt+aB2qo2LgtDoiy/3sVG8w63cgLkqFIa2NFlGpUgHFWTXkqtbgf4L5QdjRGKWhmZsnqkbtL7vkSWEcYDJ4Q==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-user-agent-browser/3.310.0: + resolution: {integrity: sha512-yU/4QnHHuQ5z3vsUqMQVfYLbZGYwpYblPiuZx4Zo9+x0PBkNjYMqctdDcrpoH9Z2xZiDN16AmQGK1tix117ZKw==} + dependencies: + '@aws-sdk/types': 3.310.0 + bowser: 2.11.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-user-agent-node/3.310.0: + resolution: {integrity: sha512-Ra3pEl+Gn2BpeE7KiDGpi4zj7WJXZA5GXnGo3mjbi9+Y3zrbuhJAbdZO3mO/o7xDgMC6ph4xCTbaSGzU6b6EDg==} + engines: {node: '>=14.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + dependencies: + '@aws-sdk/node-config-provider': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-utf8-browser/3.259.0: + resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} + dependencies: + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-utf8/3.310.0: + resolution: {integrity: sha512-DnLfFT8uCO22uOJc0pt0DsSNau1GTisngBCDw8jQuWT5CqogMJu4b/uXmwEqfj8B3GX6Xsz8zOd6JpRlPftQoA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/util-buffer-from': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/util-waiter/3.310.0: + resolution: {integrity: sha512-AV5j3guH/Y4REu+Qh3eXQU9igljHuU4XjX2sADAgf54C0kkhcCCkkiuzk3IsX089nyJCqIcj5idbjdvpnH88Vw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/abort-controller': 3.310.0 + '@aws-sdk/types': 3.310.0 + tslib: 2.5.0 + dev: true + + /@aws-sdk/xml-builder/3.310.0: + resolution: {integrity: sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.5.0 + dev: true + /@babel/code-frame/7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} @@ -1173,6 +2124,10 @@ packages: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true + /bowser/2.11.0: + resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + dev: true + /brace-expansion/1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -1298,6 +2253,14 @@ packages: string-width: 5.1.2 dev: true + /cliui/7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + /cliui/8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -1676,6 +2639,13 @@ packages: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true + /fast-xml-parser/4.1.2: + resolution: {integrity: sha512-CDYeykkle1LiA/uqQyNwYpFbyF6Axec6YapmpUP+/RHWIoR1zKjocdvNaTsxCxZzQ6v9MLXaSYm9Qq0thv0DHg==} + hasBin: true + dependencies: + strnum: 1.0.5 + dev: true + /fastq/1.14.0: resolution: {integrity: sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==} dependencies: @@ -2674,6 +3644,12 @@ packages: engines: {node: '>=12'} dev: true + /minimatch/3.0.4: + resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} + dependencies: + brace-expansion: 1.1.11 + dev: true + /minimatch/3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -3012,6 +3988,18 @@ packages: tslib: 2.4.1 dev: true + /s3-groundskeeper/0.2.2: + resolution: {integrity: sha512-62ntqZMhd7v85yWM+YXKsVLJdf6us6Lc+L52Ia91kRpZMgb/E9hjeXKsIoydgN9XoALoUEL+/Rp37LUrKOOl4Q==} + hasBin: true + dependencies: + '@aws-sdk/client-s3': 3.315.0 + minimatch: 3.0.4 + yargs: 16.2.0 + transitivePeerDependencies: + - '@aws-sdk/signature-v4-crt' + - aws-crt + dev: true + /semver/6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true @@ -3162,6 +4150,10 @@ packages: engines: {node: '>=8'} dev: true + /strnum/1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + dev: true + /supports-color/5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -3309,6 +4301,10 @@ packages: resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} dev: true + /tslib/2.5.0: + resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} + dev: true + /tsutils/3.21.0_typescript@5.0.4: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} @@ -3364,6 +4360,11 @@ packages: punycode: 2.1.1 dev: true + /uuid/8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + dev: true + /v8-compile-cache-lib/3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} dev: true @@ -3449,10 +4450,28 @@ packages: engines: {node: '>= 14'} dev: true + /yargs-parser/20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + dev: true + /yargs-parser/21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + /yargs/16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + dev: true + /yargs/17.6.2: resolution: {integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==} engines: {node: '>=12'} diff --git a/src/artifactory.mts b/src/artifactory.mts new file mode 100644 index 0000000..72c953b --- /dev/null +++ b/src/artifactory.mts @@ -0,0 +1,89 @@ +import { type ArtifactoryClient, createArtifactoryClient } from 's3-groundskeeper'; + +import { get } from './http.mjs'; + +export interface BuildsList { + buildsNumbers: { + uri: string, + started: string + }[] +} + +export interface BuildInfo { + buildInfo: { + modules: { + artifacts: Artifact[] + }[] + } +} + +export interface Artifact { + type : string, + sha1 : string, + sha256 : string, + md5 : string, + name : string +} + +export class ArtifactoryHelper { + private artifactoryClient: ArtifactoryClient; + private buildsList?: BuildsList; + + constructor(host: string, apiKey: string, user: string) { + this.artifactoryClient = createArtifactoryClient({protocol: 'https', host, apiKey, user}); + } + + public client(): ArtifactoryClient { + return this.artifactoryClient; + } + + public async artifactsByBuildNumber(project: string, buildNumber: string): Promise { + const buildInfos = await this.buildInfosByNumber(project, buildNumber); + const result: Artifact[] = []; + + for (const buildInfo of buildInfos) { + for (const module of buildInfo.buildInfo.modules) { + result.push(...module.artifacts); + } + } + + return result; + } + + private async buildInfosByNumber(project: string, buildNumber: string): Promise { + if (!this.artifactoryClient) { + throw new Error('Artifactory client does not exists'); + } + + const result: BuildInfo[] = []; + + const buildsEndpoint = this.artifactoryClient.resolveUri(`api/build/${ project }`);; + + if (!this.buildsList) { + const allBuilds = await get(buildsEndpoint); + this.buildsList = JSON.parse(allBuilds.toString()) as BuildsList; + } + + const buildTimes = (buildUri: string): Date[] => { + const times: Date[] = []; + + this.buildsList?.buildsNumbers.forEach(build => { + if (build.uri === `/${ buildUri}`) { + times.push(new Date(build.started)); + } + }); + + return times; + }; + + for (const value of buildTimes(buildNumber)) { + const buildInfoEndpoint = `${ buildsEndpoint }/${ buildNumber }?started=${ value.toISOString() }`; + const info = (await get(buildInfoEndpoint)).toString(); + const buildInfo = JSON.parse(info) as BuildInfo; + + result.push(buildInfo); + } + + return result; + } +} diff --git a/src/cli.mts b/src/cli.mts index ffb8ce0..1383c83 100644 --- a/src/cli.mts +++ b/src/cli.mts @@ -1,7 +1,7 @@ import { exit } from 'process'; import yargs from 'yargs'; -import { apply, plan } from './index.mjs'; +import { apply, createConfig, plan } from './index.mjs'; import { getMessageOfError } from './utils.mjs'; type CliType = Awaited>; @@ -37,12 +37,14 @@ async function main(): Promise { const command = cli()._[0]; + const config = await createConfig(cli().config); + if (command === 'plan') { - plan(); + plan(config); } if (command === 'apply') { - apply(); + apply(config); } return 0; diff --git a/src/config.mts b/src/config.mts index 4ad76cd..7e17f4f 100644 --- a/src/config.mts +++ b/src/config.mts @@ -1,5 +1,6 @@ import path from 'path'; import { pathToFileURL } from 'url'; +import type { DebConfig } from './deb/deb-config.mjs'; interface IOConfig { sourceDir: string; @@ -9,7 +10,7 @@ interface IOConfig { export class Config { path: string; - configFile: IOConfig | undefined; + config: (IOConfig & DebConfig) | undefined; constructor(path: string) { this.path = path; @@ -17,7 +18,7 @@ export class Config { async init(): Promise { const resolvedPath = path.resolve(this.path); - this.configFile = (await import(pathToFileURL(resolvedPath).toString())).default as IOConfig; + this.config = (await import(pathToFileURL(resolvedPath).toString())).default as (IOConfig & DebConfig); } } diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts new file mode 100644 index 0000000..2b12511 --- /dev/null +++ b/src/deb/deb-builder.mts @@ -0,0 +1,24 @@ +import type { Config } from '../config.mjs'; +import type { IBuilder } from '../ibuilder.mjs'; + +export class DebBuilder implements IBuilder { + private config: Config; + private debRepo: { + channel: string, + debs: { + name: string, + md5: string + }[]}[] = []; + + constructor(config: Config) { + this.config = config; + } + + public plan(config: Config): void { + + } + + public apply(config: Config): void { + + } +} diff --git a/src/deb/deb-config.mts b/src/deb/deb-config.mts new file mode 100644 index 0000000..c24918f --- /dev/null +++ b/src/deb/deb-config.mts @@ -0,0 +1,4 @@ +export interface DebConfig { + gpgKeyName: string; + debName: string; +} diff --git a/src/fs.mts b/src/fs.mts new file mode 100644 index 0000000..2de6d55 --- /dev/null +++ b/src/fs.mts @@ -0,0 +1,19 @@ +import { writeFileSync, mkdirSync, existsSync} from 'fs'; + +export function createFile(path: string, content: string): void { + const dirPath = path.split('/').slice(0, -1).join('/'); + + createDir(dirPath); + + writeFileSync(path, content); +} + +export function createDir(dirName: string): void { + if (!existsSync(dirName)) { + mkdirSync(dirName, { recursive: true }); + } +} + +export function createMetapointerContent(fileMd5Hash: string): string { + return `#metapointer jfrogart\noid md5:${fileMd5Hash}`; +} \ No newline at end of file diff --git a/src/http.mts b/src/http.mts new file mode 100644 index 0000000..922e4fd --- /dev/null +++ b/src/http.mts @@ -0,0 +1,91 @@ +import * as stream from 'stream'; +import { IncomingMessage } from 'http'; +import * as https from 'https'; + +export interface RequestBody { + content: string | Buffer; + contentType?: string; +} + +export interface RequestData { + headers?: Record; + body?: RequestBody; + redirectHandler?: (url: string) => string | undefined; +} + +export async function requestStream(url: string, method: string, requestData?: RequestData): Promise { + return new Promise((resolve, reject) => { + try { + const req = https.request(url, { method }); + + req + .on('response', (incomingMessage: IncomingMessage) => { + if (incomingMessage.statusCode !== 200) { + const stCode = incomingMessage.statusCode ?? 'NO_CODE'; + const stMessage = incomingMessage.statusMessage ?? 'NO_MESSAGE'; + const message = `[${method} ${url}]:${stCode}/${stMessage}`; + reject(new Error(message)); + return; + } + + resolve(incomingMessage); + }) + .on('error', (err: Error) => { + const errno = (err as {errno?: string}).errno ?? ''; + if (errno === 'ETIMEDOUT') { + reject(new Error(`Request (${url}) timeout.`)); + } + else { + reject(err); + } + }); + + if (requestData) { + if (requestData.headers) { + for (const key of Object.getOwnPropertyNames(requestData.headers)) { + const value = requestData.headers[key]; + req.setHeader(key, value); + } + } + + if (requestData.body) { + if (requestData.body.contentType) { + req.setHeader('Content-Type', requestData.body.contentType); + } + req.write(requestData.body.content); + } + } + + req.end(); + } + catch (err) { + reject(err); + } + }); +} + + +export async function request(url: string, method: string, requestData?: RequestData): Promise { + + const responseStream = await requestStream(url, method, requestData); + + let buffer: Buffer | undefined; + + for await (const item of responseStream) { + const chunk = item as Buffer; + buffer = (typeof buffer === 'undefined') ? chunk : Buffer.concat([buffer, chunk ]); + } + + return buffer ? buffer : Buffer.from(''); +} + +export function get(url: string, opt?: {stream: false} ): Promise; +export function get(url: string, opt?: {stream: true} ): Promise; + +export async function get(url: string, opt: {stream: boolean} = {stream: false}): Promise { + return opt.stream ? requestStream(url, 'GET', undefined ) : request(url, 'GET', undefined ); +} + +export function post(url: string, requestData?: RequestData): Promise { + return request(url, 'POST', requestData ); +} diff --git a/src/ibuilder.mts b/src/ibuilder.mts new file mode 100644 index 0000000..03aa295 --- /dev/null +++ b/src/ibuilder.mts @@ -0,0 +1,6 @@ +import { Config } from './config.mjs'; + +export interface IBuilder { + plan(config: Config): void; + apply(config: Config): void; +} diff --git a/src/index.mts b/src/index.mts index 338a48d..c139009 100644 --- a/src/index.mts +++ b/src/index.mts @@ -1,7 +1,11 @@ -export function plan(): void { +import { Config } from './config.mjs'; + +export { Config, createConfig } from './config.mjs'; + +export function plan(config: Config): void { console.log('plan()'); } -export function apply(): void { +export function apply(config: Config): void { console.log('apply()'); } From 2dfd854132a1f2d5aaaaa0844411c1193c24d91d Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Fri, 21 Apr 2023 11:09:37 +0300 Subject: [PATCH 02/31] conflicts resolved --- src/cli.mts | 2 +- src/http.mts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cli.mts b/src/cli.mts index 3387b3f..b1b79bb 100644 --- a/src/cli.mts +++ b/src/cli.mts @@ -15,7 +15,7 @@ async function main(): Promise { const args: CommandLineArgs = await yargsParsePromise.parse(); const command = args._[0]; - const config = await createConfig(cli().config); + const config = await createConfig(args.config); if (command === 'plan') { plan(config); diff --git a/src/http.mts b/src/http.mts index 922e4fd..b830401 100644 --- a/src/http.mts +++ b/src/http.mts @@ -44,7 +44,10 @@ export async function requestStream(url: string, method: string, requestData?: R if (requestData.headers) { for (const key of Object.getOwnPropertyNames(requestData.headers)) { const value = requestData.headers[key]; - req.setHeader(key, value); + + if (value) { + req.setHeader(key, value); + } } } From 991df403742a0a7f7551d1e4c3a3be9a845fd53d Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Thu, 27 Apr 2023 18:58:10 +0700 Subject: [PATCH 03/31] moved some parts of deb logick --- package.json | 2 + pnpm-lock.yaml | 32 +++-- src/artifacts-provider-config.mts | 12 ++ src/artifacts-provider.mts | 13 +++ src/cli.mts | 8 +- src/config.mts | 40 ++++--- src/deb/deb-builder-config.mts | 6 + src/deb/deb-builder.mts | 110 ++++++++++++++++-- src/deb/deb-config.mts | 4 - src/fs.mts | 8 +- src/http.mts | 54 +++++++-- src/ibuilder.mts | 6 +- src/index.mts | 22 +++- .../jfrog-artifacts-provider.mts} | 42 ++++--- src/repo.mts | 15 +++ 15 files changed, 301 insertions(+), 73 deletions(-) create mode 100644 src/artifacts-provider-config.mts create mode 100644 src/artifacts-provider.mts create mode 100644 src/deb/deb-builder-config.mts delete mode 100644 src/deb/deb-config.mts rename src/{artifactory.mts => jfrog/jfrog-artifacts-provider.mts} (56%) create mode 100644 src/repo.mts diff --git a/package.json b/package.json index 1d127c9..877e551 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "@tsconfig/node18": "^2.0.0", "@tsconfig/strictest": "^2.0.0", "@types/node": "18.13.0", + "@types/tar": "^6.1.4", "@types/yargs": "^17.0.16", "@typescript-eslint/eslint-plugin": "^5.45.1", "@typescript-eslint/parser": "^5.45.1", @@ -39,6 +40,7 @@ "pnpm": "8.3.1" }, "dependencies": { + "tar": "^6.1.13", "yargs": "^17.6.2" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8ace406..cec3061 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,9 @@ importers: .: dependencies: + tar: + specifier: ^6.1.13 + version: 6.1.13 yargs: specifier: ^17.6.2 version: 17.6.2 @@ -23,6 +26,9 @@ importers: '@types/node': specifier: 18.13.0 version: 18.13.0 + '@types/tar': + specifier: ^6.1.4 + version: 6.1.4 '@types/yargs': specifier: ^17.0.16 version: 17.0.20 @@ -1810,6 +1816,13 @@ packages: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} dev: true + /@types/tar@6.1.4: + resolution: {integrity: sha512-Cp4oxpfIzWt7mr2pbhHT2OTXGMAL0szYCzuf8lRWyIMCgsx6/Hfc3ubztuhvzXHXgraTQxyOCmmg7TDGIMIJJQ==} + dependencies: + '@types/node': 18.13.0 + minipass: 4.2.8 + dev: true + /@types/yargs-parser@21.0.0: resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} dev: true @@ -2231,7 +2244,6 @@ packages: /chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} - dev: true /ci-info@3.7.0: resolution: {integrity: sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==} @@ -2412,7 +2424,7 @@ packages: dependencies: https-proxy-agent: 5.0.1 node-fetch: 2.6.7 - tar: 6.1.12 + tar: 6.1.13 transitivePeerDependencies: - encoding - supports-color @@ -2722,7 +2734,6 @@ packages: engines: {node: '>= 8'} dependencies: minipass: 3.3.6 - dev: true /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -3638,7 +3649,10 @@ packages: engines: {node: '>=8'} dependencies: yallist: 4.0.0 - dev: true + + /minipass@4.2.8: + resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} + engines: {node: '>=8'} /minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} @@ -3646,13 +3660,11 @@ packages: dependencies: minipass: 3.3.6 yallist: 4.0.0 - dev: true /mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} hasBin: true - dev: true /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -4157,17 +4169,16 @@ packages: engines: {node: '>= 0.4'} dev: true - /tar@6.1.12: - resolution: {integrity: sha512-jU4TdemS31uABHd+Lt5WEYJuzn+TJTCBLljvIAHZOz6M9Os5pJ4dD+vRFLxPa/n3T0iEFzpi+0x1UfuDZYbRMw==} + /tar@6.1.13: + resolution: {integrity: sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==} engines: {node: '>=10'} dependencies: chownr: 2.0.0 fs-minipass: 2.1.0 - minipass: 3.3.6 + minipass: 4.2.8 minizlib: 2.1.2 mkdirp: 1.0.4 yallist: 4.0.0 - dev: true /test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} @@ -4421,7 +4432,6 @@ packages: /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true /yaml@2.1.3: resolution: {integrity: sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==} diff --git a/src/artifacts-provider-config.mts b/src/artifacts-provider-config.mts new file mode 100644 index 0000000..50edcf1 --- /dev/null +++ b/src/artifacts-provider-config.mts @@ -0,0 +1,12 @@ +export type ProviderType = 'jfrog'; + +export interface ArtifactsProviderConfig { + artifactsProvider: { + type: ProviderType, + protocol: string, + host: string, + project: string, + apiKey: string, + user: string + } +} \ No newline at end of file diff --git a/src/artifacts-provider.mts b/src/artifacts-provider.mts new file mode 100644 index 0000000..a5c28b8 --- /dev/null +++ b/src/artifacts-provider.mts @@ -0,0 +1,13 @@ +export interface Artifact { + name: string, + type: string, + path: string, + sha1: string, + sha256: string, + md5: string +} + +export interface ArtifactsProvider { + artifactsByBuildNumber(buildNumber: string): Promise; + artifactUrl(artifact: Artifact): string; +} diff --git a/src/cli.mts b/src/cli.mts index b1b79bb..cd51486 100644 --- a/src/cli.mts +++ b/src/cli.mts @@ -1,7 +1,7 @@ import { exit } from 'process'; import yargs from 'yargs'; -import { apply, createConfig, plan } from './index.mjs'; +import { apply, createConfigProvider, plan } from './index.mjs'; import { getMessageOfError } from './utils.mjs'; type CommandLineArgs = Awaited>; @@ -15,14 +15,14 @@ async function main(): Promise { const args: CommandLineArgs = await yargsParsePromise.parse(); const command = args._[0]; - const config = await createConfig(args.config); + const configProvider = await createConfigProvider(args.config); if (command === 'plan') { - plan(config); + plan(configProvider.config); } if (command === 'apply') { - apply(config); + apply(configProvider.config); } return 0; diff --git a/src/config.mts b/src/config.mts index 7e17f4f..6354ace 100644 --- a/src/config.mts +++ b/src/config.mts @@ -1,16 +1,22 @@ import path from 'path'; import { pathToFileURL } from 'url'; -import type { DebConfig } from './deb/deb-config.mjs'; -interface IOConfig { - sourceDir: string; - repoOut: string; - repoDir: string; +import type { DebBuilderConfig } from './deb/deb-builder-config.mjs'; +import type { ArtifactsProviderConfig } from './artifacts-provider-config.mjs'; +import type { Repo } from './repo.mjs'; + +interface BaseConfig { + base: { + out: string; + repo: Repo; + } } -export class Config { - path: string; - config: (IOConfig & DebConfig) | undefined; +export type Config = BaseConfig & DebBuilderConfig & ArtifactsProviderConfig; + +export class ConfigProvider { + private path: string; + private configInstance: Config | undefined; constructor(path: string) { this.path = path; @@ -18,14 +24,22 @@ export class Config { async init(): Promise { const resolvedPath = path.resolve(this.path); - this.config = (await import(pathToFileURL(resolvedPath).toString())).default as (IOConfig & DebConfig); + this.configInstance = (await import(pathToFileURL(resolvedPath).toString())).default as Config; + } + + get config(): Config { + if (!this.configInstance) { + throw new Error('Config not initialized'); + } + + return this.configInstance; } } -export async function createConfig(path: string): Promise { - const configurationInstance = new Config(path); - await configurationInstance.init(); +export async function createConfigProvider(path: string): Promise { + const configProviderInstance = new ConfigProvider(path); + await configProviderInstance.init(); - return configurationInstance; + return configProviderInstance; } diff --git a/src/deb/deb-builder-config.mts b/src/deb/deb-builder-config.mts new file mode 100644 index 0000000..82e4790 --- /dev/null +++ b/src/deb/deb-builder-config.mts @@ -0,0 +1,6 @@ +export interface DebBuilderConfig { + debBuilder: { + gpgKeyName: string; + repoName: string; + } +} diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index 2b12511..a64bdbd 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -1,24 +1,120 @@ -import type { Config } from '../config.mjs'; +import type { Artifact, ArtifactsProvider } from '../artifacts-provider.mjs'; +import { createDir, removeDir } from '../fs.mjs'; import type { IBuilder } from '../ibuilder.mjs'; +import { requestRange } from '../http.mjs'; +import type { Config } from '../config.mjs'; +import * as path from 'path'; +import * as fs from 'fs'; +import * as tar from 'tar'; export class DebBuilder implements IBuilder { - private config: Config; + private readonly config: Config; + private readonly artifactsProvider: ArtifactsProvider; + + private readonly pool: string; + private readonly dists: string; + private readonly keys: string; + private debRepo: { channel: string, debs: { - name: string, - md5: string + version: string, + url: string, + arch: string, + artifact: Artifact }[]}[] = []; - constructor(config: Config) { + constructor(artifactsProvider: ArtifactsProvider, config: Config) { this.config = config; + + this.pool = `${ this.config.base.out }/repo/${ this.config.debBuilder.repoName }/deb/pool`; + this.dists = `${ this.config.base.out }/repo/${ this.config.debBuilder.repoName }/deb/dists`; + this.keys = `${ this.config.base.out }/repo/${ this.config.debBuilder.repoName }/deb/keys`; + this.keys; + this.artifactsProvider = artifactsProvider; } - public plan(config: Config): void { + public async plan(): Promise { + for (const entry of this.config.base.repo) { + let debs: { + version: string, + url: string, + arch: string, + artifact: Artifact + }[] = []; + + for (const pack of entry.packages.packages) { + const debArtifactItems = (await this.artifactsProvider.artifactsByBuildNumber(pack.buildNumber)).filter(artifact => artifact.type === 'deb'); + + for (const artifact of debArtifactItems) { + const arch = 'hui'; + debs.push({ + version: pack.version, + url: this.artifactsProvider.artifactUrl(artifact), + arch: arch, + artifact: artifact + }); + } + } + + this.debRepo.push({ channel: entry.channel, debs }); + } + + + for (const channel of this.debRepo) { + for (const deb of channel.debs) { + const debUrl = await this.artifactsProvider.artifactUrl(deb.artifact); + const controlTarSizeRange = '120-129'; + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call + const cocntrolTarSize = Number((await requestRange(debUrl, controlTarSizeRange)).read().toString().trim()); + const controlTarRange = `132-${ 131 + cocntrolTarSize }`; + const controlTar = await requestRange(debUrl, controlTarRange); + + const whereExtract = path.join(this.dists, channel.channel, 'main', `binary-${ deb.arch }`, path.basename(debUrl, '.deb')); + + createDir(whereExtract); + + await new Promise((resolve) => { + controlTar + .pipe(tar.extract({ cwd: whereExtract, strip: 1 }, ['./control'])) + .on('finish', () => { + const targetMetaPath = path.join(this.dists, channel.channel, 'main', `binary-${ deb.arch }`, `${ this.debName(deb) }.meta`); + fs.renameSync(path.join(whereExtract, 'control'), targetMetaPath); + + removeDir(whereExtract); + + const fileName = path.relative(`${ this.config.base.out }/repo/${ this.config.debBuilder.repoName }/deb`, path.join(this.pool, 'main', `t/tradingviewdesktop-${ channel.channel }`, this.debName(deb))); + const debSize = controlTar.headers['content-range']?.split('/')[1]; + const sha1 = controlTar.headers['x-checksum-sha1']; + const sha256 = controlTar.headers['x-checksum-sha256']; + const md5 = controlTar.headers['x-checksum-md5']; + + if (typeof sha1 !== 'string' || typeof sha256 !== 'string' || typeof md5 !== 'string' || typeof debSize !== 'string') { + throw new Error('No checksum was found in headers'); + } + + const dataToAppend = `Filename: ${ fileName }\nSize: ${ debSize }\nSHA1: ${ sha1 }\nSHA256: ${ sha256 }\nMD5Sum: ${ md5 }\n`; + + fs.appendFile(targetMetaPath, dataToAppend, (err) => { + if (err) { + throw err; + } + + resolve(); + }); + }); + }); + } + } } - public apply(config: Config): void { + public apply(): void { + + } + private debName(deb: { version: string, arch: string }): string { + return `${ this.config.debBuilder.repoName }-${ deb.version }_${ deb.arch }.deb`; } } diff --git a/src/deb/deb-config.mts b/src/deb/deb-config.mts deleted file mode 100644 index c24918f..0000000 --- a/src/deb/deb-config.mts +++ /dev/null @@ -1,4 +0,0 @@ -export interface DebConfig { - gpgKeyName: string; - debName: string; -} diff --git a/src/fs.mts b/src/fs.mts index 2de6d55..615639c 100644 --- a/src/fs.mts +++ b/src/fs.mts @@ -1,4 +1,4 @@ -import { writeFileSync, mkdirSync, existsSync} from 'fs'; +import { writeFileSync, mkdirSync, existsSync, rmdirSync } from 'fs'; export function createFile(path: string, content: string): void { const dirPath = path.split('/').slice(0, -1).join('/'); @@ -14,6 +14,12 @@ export function createDir(dirName: string): void { } } +export function removeDir(dirName: string): void { + if (existsSync(dirName)) { + rmdirSync(dirName, {recursive: true}); + } +} + export function createMetapointerContent(fileMd5Hash: string): string { return `#metapointer jfrogart\noid md5:${fileMd5Hash}`; } \ No newline at end of file diff --git a/src/http.mts b/src/http.mts index b830401..e52e9e5 100644 --- a/src/http.mts +++ b/src/http.mts @@ -1,6 +1,5 @@ -import * as stream from 'stream'; -import { IncomingMessage } from 'http'; -import * as https from 'https'; +import { Readable } from 'stream'; +import { IncomingMessage, request as httpRequest } from 'http'; export interface RequestBody { content: string | Buffer; @@ -16,7 +15,7 @@ export interface RequestData { export async function requestStream(url: string, method: string, requestData?: RequestData): Promise { return new Promise((resolve, reject) => { try { - const req = https.request(url, { method }); + const req = httpRequest(url, { method }); req .on('response', (incomingMessage: IncomingMessage) => { @@ -67,7 +66,6 @@ export async function requestStream(url: string, method: string, requestData?: R }); } - export async function request(url: string, method: string, requestData?: RequestData): Promise { const responseStream = await requestStream(url, method, requestData); @@ -82,10 +80,52 @@ export async function request(url: string, method: string, requestData?: Request return buffer ? buffer : Buffer.from(''); } +export async function requestRange(url: string, range: string): Promise { + return new Promise((resolve, reject) => { + try { + const req = httpRequest(url, { method: 'GET' }); + + req.on('response', (incomingMessage: IncomingMessage) => { + if (incomingMessage.statusCode === 206) { + resolve(incomingMessage); + return; + } + + if (incomingMessage.statusCode !== 200) { + const stCode = incomingMessage.statusCode ?? 'NO_CODE'; + const stMessage = incomingMessage.statusMessage ?? 'NO_MESSAGE'; + const message = `[GET ${url}]:${stCode}/${stMessage}`; + reject(new Error(message)); + return; + } + + resolve(incomingMessage); + }) + .on('error', (err: Error) => { + const errno = (err as {errno?: string}).errno ?? ''; + if (errno === 'ETIMEDOUT') { + reject(new Error(`Request (${url}) timeout.`)); + } + else { + reject(err); + } + }); + + + req.setHeader('Range', `bytes=${ range }`); + + req.end(); + } + catch (err) { + reject(err); + } + }); +} + export function get(url: string, opt?: {stream: false} ): Promise; -export function get(url: string, opt?: {stream: true} ): Promise; +export function get(url: string, opt?: {stream: true} ): Promise; -export async function get(url: string, opt: {stream: boolean} = {stream: false}): Promise { +export async function get(url: string, opt: {stream: boolean} = {stream: false}): Promise { return opt.stream ? requestStream(url, 'GET', undefined ) : request(url, 'GET', undefined ); } diff --git a/src/ibuilder.mts b/src/ibuilder.mts index 03aa295..3e1a283 100644 --- a/src/ibuilder.mts +++ b/src/ibuilder.mts @@ -1,6 +1,4 @@ -import { Config } from './config.mjs'; - export interface IBuilder { - plan(config: Config): void; - apply(config: Config): void; + plan(): Promise; + apply(): void; } diff --git a/src/index.mts b/src/index.mts index c139009..2a43588 100644 --- a/src/index.mts +++ b/src/index.mts @@ -1,11 +1,27 @@ -import { Config } from './config.mjs'; +import type { Config } from './config.mjs'; +import type { IBuilder } from './ibuilder.mjs'; +import { JfrogArtifactsProvider } from './jfrog/jfrog-artifacts-provider.mjs'; +import { DebBuilder } from './deb/deb-builder.mjs'; -export { Config, createConfig } from './config.mjs'; +export { type Config, createConfigProvider } from './config.mjs'; + +export async function plan(config: Config): Promise { + const artifactsProvider = new JfrogArtifactsProvider(config); + + let builders: IBuilder[] = []; + + if (config.debBuilder) { + builders.push(new DebBuilder(artifactsProvider, config)); + } + + for (const builder of builders) { + await builder.plan(); + } -export function plan(config: Config): void { console.log('plan()'); } export function apply(config: Config): void { + config; console.log('apply()'); } diff --git a/src/artifactory.mts b/src/jfrog/jfrog-artifacts-provider.mts similarity index 56% rename from src/artifactory.mts rename to src/jfrog/jfrog-artifacts-provider.mts index 72c953b..52b8c19 100644 --- a/src/artifactory.mts +++ b/src/jfrog/jfrog-artifacts-provider.mts @@ -1,6 +1,8 @@ import { type ArtifactoryClient, createArtifactoryClient } from 's3-groundskeeper'; -import { get } from './http.mjs'; +import { get } from '../http.mjs'; +import type { Artifact, ArtifactsProvider } from '../artifacts-provider.mjs'; +import type { ArtifactsProviderConfig } from '../artifacts-provider-config.mjs'; export interface BuildsList { buildsNumbers: { @@ -17,28 +19,24 @@ export interface BuildInfo { } } -export interface Artifact { - type : string, - sha1 : string, - sha256 : string, - md5 : string, - name : string -} - -export class ArtifactoryHelper { +export class JfrogArtifactsProvider implements ArtifactsProvider { private artifactoryClient: ArtifactoryClient; private buildsList?: BuildsList; - constructor(host: string, apiKey: string, user: string) { - this.artifactoryClient = createArtifactoryClient({protocol: 'https', host, apiKey, user}); - } + private readonly config: ArtifactsProviderConfig; - public client(): ArtifactoryClient { - return this.artifactoryClient; + constructor(config: ArtifactsProviderConfig) { + this.config = config; + this.artifactoryClient = createArtifactoryClient({ + protocol: this.config.artifactsProvider.protocol, + host: this.config.artifactsProvider.host, + apiKey: this.config.artifactsProvider.apiKey, + user: this.config.artifactsProvider.user + }); } - public async artifactsByBuildNumber(project: string, buildNumber: string): Promise { - const buildInfos = await this.buildInfosByNumber(project, buildNumber); + public async artifactsByBuildNumber(buildNumber: string): Promise { + const buildInfos = await this.buildInfosByNumber(buildNumber); const result: Artifact[] = []; for (const buildInfo of buildInfos) { @@ -50,14 +48,20 @@ export class ArtifactoryHelper { return result; } - private async buildInfosByNumber(project: string, buildNumber: string): Promise { + public artifactUrl(artifact: Artifact): string { + const baseUrl = `${ this.config.artifactsProvider.protocol }://${ this.config.artifactsProvider.host }/artifactory`; + + return `${ baseUrl }/${ artifact.path }`; + } + + private async buildInfosByNumber(buildNumber: string): Promise { if (!this.artifactoryClient) { throw new Error('Artifactory client does not exists'); } const result: BuildInfo[] = []; - const buildsEndpoint = this.artifactoryClient.resolveUri(`api/build/${ project }`);; + const buildsEndpoint = this.artifactoryClient.resolveUri(`api/build/${ this.config.artifactsProvider.project }`);; if (!this.buildsList) { const allBuilds = await get(buildsEndpoint); diff --git a/src/repo.mts b/src/repo.mts new file mode 100644 index 0000000..6fca0fb --- /dev/null +++ b/src/repo.mts @@ -0,0 +1,15 @@ +export interface Package { + version: string, + buildNumber: string +} + +export interface Packages { + packages: Package[], + highest: Package, +} + +export type Channel = string; +export type Repo = { + channel: Channel, + packages: Packages +}[] From ba9d0d6efa3a8b5a319c15dca7e6afe0fe248147 Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Mon, 15 May 2023 14:33:32 +0300 Subject: [PATCH 04/31] lot of deb builder functionality --- .gitignore | 1 + .vscode/launch.json | 13 +- package.json | 2 + pnpm-lock.yaml | 15 ++ src/artifacts-provider.mts | 2 +- src/cli.mts | 2 +- src/deb/deb-builder-config.mts | 4 +- src/deb/deb-builder.mts | 204 +++++++++++++++++++------ src/http.mts | 10 +- src/jfrog/jfrog-artifacts-provider.mts | 22 ++- 10 files changed, 218 insertions(+), 57 deletions(-) diff --git a/.gitignore b/.gitignore index 56c9d65..af489f5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules/ # build output directories dist/ +out/ # coverage report directory /coverage/ diff --git a/.vscode/launch.json b/.vscode/launch.json index 5efcca3..b0fefb7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ { "type": "node", "request": "launch", - "name": "Start", + "name": "Start plan command", "runtimeArgs": [ ], "program": "${workspaceFolder}/dist/cli.mjs", @@ -13,6 +13,17 @@ "plan" ] }, + { + "type": "node", + "request": "launch", + "name": "Start apply command", + "runtimeArgs": [ + ], + "program": "${workspaceFolder}/dist/cli.mjs", + "args": [ + "apply" + ] + }, { "type": "node", "name": "vscode-jest-tests.v2", diff --git a/package.json b/package.json index 877e551..0698b01 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "@tsconfig/esm": "^1.0.2", "@tsconfig/node18": "^2.0.0", "@tsconfig/strictest": "^2.0.0", + "@types/ini": "^1.3.31", "@types/node": "18.13.0", "@types/tar": "^6.1.4", "@types/yargs": "^17.0.16", @@ -40,6 +41,7 @@ "pnpm": "8.3.1" }, "dependencies": { + "ini": "^4.1.0", "tar": "^6.1.13", "yargs": "^17.6.2" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cec3061..54918c6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,9 @@ importers: .: dependencies: + ini: + specifier: ^4.1.0 + version: 4.1.0 tar: specifier: ^6.1.13 version: 6.1.13 @@ -23,6 +26,9 @@ importers: '@tsconfig/strictest': specifier: ^2.0.0 version: 2.0.0 + '@types/ini': + specifier: ^1.3.31 + version: 1.3.31 '@types/node': specifier: 18.13.0 version: 18.13.0 @@ -1780,6 +1786,10 @@ packages: '@types/node': 18.13.0 dev: true + /@types/ini@1.3.31: + resolution: {integrity: sha512-8ecxxaG4AlVEM1k9+BsziMw8UsX0qy3jYI1ad/71RrDZ+rdL6aZB0wLfAuflQiDhkD5o4yJ0uPK3OSUic3fG0w==} + dev: true + /@types/istanbul-lib-coverage@2.0.4: resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} dev: true @@ -2917,6 +2927,11 @@ packages: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} dev: true + /ini@4.1.0: + resolution: {integrity: sha512-HLR38RSF2iulAzc3I/sma4CoYxQP844rPYCNfzGDOHqa/YqVlwuuZgBx6M50/X8dKgzk0cm1qRg3+47mK2N+cQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: false + /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true diff --git a/src/artifacts-provider.mts b/src/artifacts-provider.mts index a5c28b8..295f449 100644 --- a/src/artifacts-provider.mts +++ b/src/artifacts-provider.mts @@ -9,5 +9,5 @@ export interface Artifact { export interface ArtifactsProvider { artifactsByBuildNumber(buildNumber: string): Promise; - artifactUrl(artifact: Artifact): string; + artifactUrl(artifact: Artifact): Promise; } diff --git a/src/cli.mts b/src/cli.mts index cd51486..e63a4b0 100644 --- a/src/cli.mts +++ b/src/cli.mts @@ -18,7 +18,7 @@ async function main(): Promise { const configProvider = await createConfigProvider(args.config); if (command === 'plan') { - plan(configProvider.config); + await plan(configProvider.config); } if (command === 'apply') { diff --git a/src/deb/deb-builder-config.mts b/src/deb/deb-builder-config.mts index 82e4790..059ce4a 100644 --- a/src/deb/deb-builder-config.mts +++ b/src/deb/deb-builder-config.mts @@ -1,6 +1,8 @@ export interface DebBuilderConfig { debBuilder: { + gpgPublicKeyPath: string; gpgKeyName: string; - repoName: string; + applicationName: string; + component: string; } } diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index a64bdbd..5035308 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -6,6 +6,19 @@ import type { Config } from '../config.mjs'; import * as path from 'path'; import * as fs from 'fs'; import * as tar from 'tar'; +import * as ini from 'ini'; +import * as crypto from 'crypto'; +import * as os from 'os'; +import { createGzip } from 'zlib'; +import { spawnSync } from 'child_process'; + +const ReleaseFileTemplate = +`Origin: $ORIGIN +Label: Ubuntu/Debian +Architecture: $ARCH +Component: $COMPONENT +Codename: $CHANNEL\n`; + export class DebBuilder implements IBuilder { private readonly config: Config; @@ -20,16 +33,15 @@ export class DebBuilder implements IBuilder { debs: { version: string, url: string, - arch: string, artifact: Artifact }[]}[] = []; constructor(artifactsProvider: ArtifactsProvider, config: Config) { this.config = config; - this.pool = `${ this.config.base.out }/repo/${ this.config.debBuilder.repoName }/deb/pool`; - this.dists = `${ this.config.base.out }/repo/${ this.config.debBuilder.repoName }/deb/dists`; - this.keys = `${ this.config.base.out }/repo/${ this.config.debBuilder.repoName }/deb/keys`; + this.pool = `${ this.config.base.out }/repo/${ this.config.debBuilder.applicationName }/deb/pool`; + this.dists = `${ this.config.base.out }/repo/${ this.config.debBuilder.applicationName }/deb/dists`; + this.keys = `${ this.config.base.out }/repo/${ this.config.debBuilder.applicationName }/deb/keys`; this.keys; this.artifactsProvider = artifactsProvider; } @@ -39,7 +51,6 @@ export class DebBuilder implements IBuilder { let debs: { version: string, url: string, - arch: string, artifact: Artifact }[] = []; @@ -47,11 +58,9 @@ export class DebBuilder implements IBuilder { const debArtifactItems = (await this.artifactsProvider.artifactsByBuildNumber(pack.buildNumber)).filter(artifact => artifact.type === 'deb'); for (const artifact of debArtifactItems) { - const arch = 'hui'; debs.push({ version: pack.version, - url: this.artifactsProvider.artifactUrl(artifact), - arch: arch, + url: await this.artifactsProvider.artifactUrl(artifact), artifact: artifact }); } @@ -62,59 +71,158 @@ export class DebBuilder implements IBuilder { for (const channel of this.debRepo) { - for (const deb of channel.debs) { - const debUrl = await this.artifactsProvider.artifactUrl(deb.artifact); - const controlTarSizeRange = '120-129'; - - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call - const cocntrolTarSize = Number((await requestRange(debUrl, controlTarSizeRange)).read().toString().trim()); - const controlTarRange = `132-${ 131 + cocntrolTarSize }`; - const controlTar = await requestRange(debUrl, controlTarRange); - - const whereExtract = path.join(this.dists, channel.channel, 'main', `binary-${ deb.arch }`, path.basename(debUrl, '.deb')); - - createDir(whereExtract); - - await new Promise((resolve) => { - controlTar - .pipe(tar.extract({ cwd: whereExtract, strip: 1 }, ['./control'])) - .on('finish', () => { - const targetMetaPath = path.join(this.dists, channel.channel, 'main', `binary-${ deb.arch }`, `${ this.debName(deb) }.meta`); - fs.renameSync(path.join(whereExtract, 'control'), targetMetaPath); + for (const deb of channel.debs) { + const debUrl = deb.url; + const controlTarSizeRange = '120-129'; + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call + const cocntrolTarSize = Number((await requestRange(debUrl, controlTarSizeRange)).read().toString().trim()); + const controlTarRange = `132-${ 131 + cocntrolTarSize }`; + const controlTar = await requestRange(debUrl, controlTarRange); + + const whereExtract = path.join(os.tmpdir(), `control-${ crypto.randomBytes(4).toString('hex')}`); + + createDir(whereExtract); + + await new Promise((resolve) => { + controlTar + .pipe(tar.extract({ cwd: whereExtract, strip: 1 }, ['./control'])) + .on('finish', () => { + const controlMetaContent = fs.readFileSync(path.join(whereExtract, 'control'), 'utf-8').replaceAll(':', '='); + const controlMeta = ini.parse(controlMetaContent); + + const targetMetaPath = path.join(this.dists, channel.channel, this.config.debBuilder.component, `binary-${ controlMeta['Architecture'] }`, `${ this.debName(deb.version, controlMeta['Architecture']) }.meta`); + createDir(path.dirname(targetMetaPath)); + fs.renameSync(path.join(whereExtract, 'control'), targetMetaPath); removeDir(whereExtract); - const fileName = path.relative(`${ this.config.base.out }/repo/${ this.config.debBuilder.repoName }/deb`, path.join(this.pool, 'main', `t/tradingviewdesktop-${ channel.channel }`, this.debName(deb))); - const debSize = controlTar.headers['content-range']?.split('/')[1]; - const sha1 = controlTar.headers['x-checksum-sha1']; - const sha256 = controlTar.headers['x-checksum-sha256']; - const md5 = controlTar.headers['x-checksum-md5']; + const fileName = path.relative(`${ this.config.base.out }/repo/${ this.config.debBuilder.applicationName }/deb`, path.join(this.pool, this.config.debBuilder.component, `${ this.config.debBuilder.applicationName[0]}/${ this.config.debBuilder.applicationName}-${ channel.channel }`, this.debName(deb.version, controlMeta['Architecture']))); + const debSize = controlTar.headers['content-range']?.split('/')[1]; + const sha1 = controlTar.headers['x-checksum-sha1']; + const sha256 = controlTar.headers['x-checksum-sha256']; + const md5 = controlTar.headers['x-checksum-md5']; - if (typeof sha1 !== 'string' || typeof sha256 !== 'string' || typeof md5 !== 'string' || typeof debSize !== 'string') { - throw new Error('No checksum was found in headers'); - } + if (typeof sha1 !== 'string' || typeof sha256 !== 'string' || typeof md5 !== 'string' || typeof debSize !== 'string') { + throw new Error('No checksum was found in headers'); + } - const dataToAppend = `Filename: ${ fileName }\nSize: ${ debSize }\nSHA1: ${ sha1 }\nSHA256: ${ sha256 }\nMD5Sum: ${ md5 }\n`; + const dataToAppend = `Filename: ${ fileName }\nSize: ${ debSize }\nSHA1: ${ sha1 }\nSHA256: ${ sha256 }\nMD5Sum: ${ md5 }\n`; - fs.appendFile(targetMetaPath, dataToAppend, (err) => { - if (err) { - throw err; - } + fs.appendFile(targetMetaPath, dataToAppend, (err) => { + if (err) { + throw err; + } - resolve(); - }); - }); - }); - } - } + resolve(); + }); + }); + }); + } + } + + const compressFile = async (input: string): Promise => { + return new Promise((resolve) => { + const inp = fs.createReadStream(input); + const out = fs.createWriteStream(`${ input }.gz`); + + const gzip = createGzip({ level: 9 }); + + inp.pipe(gzip).pipe(out).on('finish', () => { + resolve(); + }); + }); + } + + for (const chan of this.debRepo) { + const distsRoot = path.join(this.dists, chan.channel, this.config.debBuilder.component); + const distsByArch = fs.readdirSync(distsRoot).map(dist => path.join(distsRoot, dist)); + + for (const dist of distsByArch) { + const targetPackagesFile = path.join(dist, 'Packages'); + const metaFiles = fs.readdirSync(dist) + .filter(fileName => fileName.endsWith('.meta')) + .map(metaFile => path.join(dist, metaFile)); + + let packagesContent = ''; + + for (const metaFile of metaFiles) { + packagesContent += fs.readFileSync(metaFile); + packagesContent += '\n'; + fs.unlinkSync(metaFile); + } + + fs.writeFileSync(targetPackagesFile, packagesContent); + await compressFile(targetPackagesFile); + } + } } public apply(): void { } - private debName(deb: { version: string, arch: string }): string { - return `${ this.config.debBuilder.repoName }-${ deb.version }_${ deb.arch }.deb`; + private debName(version: string, arch: string): string { + return `${ this.config.debBuilder.applicationName }-${ version }_${ arch }.deb`; } + + private async makeRelease(): Promise { + console.log('DebBuilder: makeRelease'); + + const publicKeyPath = path.join(this.keys, 'desktop.asc'); + await fs.promises.copyFile(this.config.debBuilder.gpgPublicKeyPath, publicKeyPath); + + for (const chanDebs of this.debRepo) { + const releaseContent = ReleaseFileTemplate + .replace('$CHANNEL', chanDebs.channel) + .replace('$ARCH', this.arch) + .replace('$COMPONENT', this.config.debBuilder.component); + + const releasePath = path.join(this.dists, chanDebs.channel, 'main', `binary-${ this.arch }`, 'Release'); + const releaseFilePath = path.join(this.dists, chanDebs.channel, 'Release'); + const releaseGpgFilePath = path.join(this.dists, chanDebs.channel, 'Release.gpg'); + const inReleaseFilePath = path.join(this.dists, chanDebs.channel, 'InRelease'); + + await fs.promises.writeFile(releasePath, releaseContent); + await fs.promises.copyFile(releasePath, releaseFilePath); + + await this.execToolToFile('apt-ftparchive', ['release', `${ this.dists }/${ chanDebs.channel }`], releaseFilePath, true); + await this.execToolToFile('gpg', ['--default-key', this.config.debBuilder.gpgKeyName, '-abs', '-o', releaseGpgFilePath, releaseFilePath]); + await this.execToolToFile('gpg', ['--default-key', this.config.debBuilder.gpgKeyName, '--clearsign', '-o', inReleaseFilePath, releaseFilePath]); + } + } + + private async execToolToFile(tool: string, args: string[], outputPath?: string, append?: boolean): Promise { + if (!append && outputPath && fs.existsSync(outputPath)) { + await fs.promises.unlink(outputPath); + } + + const toolProcessResult = spawnSync(tool, args, {stdio: 'pipe', encoding: 'utf-8'}); + const toolOutput = toolProcessResult.stdout; + + const dumpToolOutput = (): void => { + const toolErrOutput = toolProcessResult.stderr; + if (toolOutput && toolOutput.length > 0) { + console.log(toolOutput); + } + if (toolErrOutput && toolErrOutput.length > 0) { + console.warn(toolErrOutput); + } + }; + + if (outputPath) { + console.log(`Execute ${tool} ${args.join(' ')} => ${outputPath}`); + dumpToolOutput(); + if (append) { + return fs.promises.appendFile(outputPath, toolOutput); + } + + return fs.promises.writeFile(outputPath, toolOutput); + } + else { + console.log(`Execute ${tool} ${args.join(' ')}`); + dumpToolOutput(); + } + } } diff --git a/src/http.mts b/src/http.mts index e52e9e5..66eab04 100644 --- a/src/http.mts +++ b/src/http.mts @@ -1,5 +1,6 @@ import { Readable } from 'stream'; -import { IncomingMessage, request as httpRequest } from 'http'; +import { request as httpRequest } from 'https'; +import type { IncomingMessage } from 'http'; export interface RequestBody { content: string | Buffer; @@ -19,6 +20,12 @@ export async function requestStream(url: string, method: string, requestData?: R req .on('response', (incomingMessage: IncomingMessage) => { + if (incomingMessage.statusCode === 301) { + if (incomingMessage.headers.location) { + return requestStream(incomingMessage.headers.location, method, requestData); + } + } + if (incomingMessage.statusCode !== 200) { const stCode = incomingMessage.statusCode ?? 'NO_CODE'; const stMessage = incomingMessage.statusMessage ?? 'NO_MESSAGE'; @@ -28,6 +35,7 @@ export async function requestStream(url: string, method: string, requestData?: R } resolve(incomingMessage); + return; }) .on('error', (err: Error) => { const errno = (err as {errno?: string}).errno ?? ''; diff --git a/src/jfrog/jfrog-artifacts-provider.mts b/src/jfrog/jfrog-artifacts-provider.mts index 52b8c19..5023f3d 100644 --- a/src/jfrog/jfrog-artifacts-provider.mts +++ b/src/jfrog/jfrog-artifacts-provider.mts @@ -1,4 +1,4 @@ -import { type ArtifactoryClient, createArtifactoryClient } from 's3-groundskeeper'; +import { type ArtifactoryClient, createArtifactoryClient, type ArtifactoryItemMeta } from 's3-groundskeeper'; import { get } from '../http.mjs'; import type { Artifact, ArtifactsProvider } from '../artifacts-provider.mjs'; @@ -48,10 +48,24 @@ export class JfrogArtifactsProvider implements ArtifactsProvider { return result; } - public artifactUrl(artifact: Artifact): string { - const baseUrl = `${ this.config.artifactsProvider.protocol }://${ this.config.artifactsProvider.host }/artifactory`; + public async artifactUrl(artifact: Artifact): Promise { + const aqlItemField = 'actual_md5'; + + const artQueryResult = await this.artifactoryClient.query(`items.find({"${aqlItemField}": "${artifact.md5}"}).include("*")`); + if (artQueryResult.results.length === 0) { + throw new Error(`No artifactory item found for ("${aqlItemField}": "${artifact.md5}"}`); + } + else if (artQueryResult.results.length > 1) { + throw new Error(`Expected single artifactory item for ("${aqlItemField}": "${artifact.md5}"}`); + } + + const item = artQueryResult.results[0]; + + if (!item) { + throw new Error(`No artifactory item found for ("${aqlItemField}": "${artifact.md5}"}`); + } - return `${ baseUrl }/${ artifact.path }`; + return this.artifactoryClient.resolveUri(item); } private async buildInfosByNumber(buildNumber: string): Promise { From 6b15b16df2778492afd9969a40f591444b32f181 Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Tue, 16 May 2023 12:51:43 +0300 Subject: [PATCH 05/31] make release file and sign it --- src/deb/deb-builder-config.mts | 1 + src/deb/deb-builder.mts | 38 ++++++++++++++++++---------------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/deb/deb-builder-config.mts b/src/deb/deb-builder-config.mts index 059ce4a..62a9d13 100644 --- a/src/deb/deb-builder-config.mts +++ b/src/deb/deb-builder-config.mts @@ -4,5 +4,6 @@ export interface DebBuilderConfig { gpgKeyName: string; applicationName: string; component: string; + origin: string; } } diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index 5035308..e61b5a7 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -156,6 +156,8 @@ export class DebBuilder implements IBuilder { await compressFile(targetPackagesFile); } + + await this.makeRelease(chan.channel, 'amd64'); } } @@ -167,30 +169,30 @@ export class DebBuilder implements IBuilder { return `${ this.config.debBuilder.applicationName }-${ version }_${ arch }.deb`; } - private async makeRelease(): Promise { + private async makeRelease(channel: string, arch: string): Promise { console.log('DebBuilder: makeRelease'); - const publicKeyPath = path.join(this.keys, 'desktop.asc'); - await fs.promises.copyFile(this.config.debBuilder.gpgPublicKeyPath, publicKeyPath); + const publicKeyPath = path.join(this.keys, 'desktop.asc'); + createDir(this.keys); + await fs.promises.copyFile(this.config.debBuilder.gpgPublicKeyPath, publicKeyPath); - for (const chanDebs of this.debRepo) { - const releaseContent = ReleaseFileTemplate - .replace('$CHANNEL', chanDebs.channel) - .replace('$ARCH', this.arch) - .replace('$COMPONENT', this.config.debBuilder.component); + const releaseContent = ReleaseFileTemplate + .replace('$ORIGIN', this.config.debBuilder.origin) + .replace('$CHANNEL', channel) + .replace('$ARCH', arch) + .replace('$COMPONENT', this.config.debBuilder.component); - const releasePath = path.join(this.dists, chanDebs.channel, 'main', `binary-${ this.arch }`, 'Release'); - const releaseFilePath = path.join(this.dists, chanDebs.channel, 'Release'); - const releaseGpgFilePath = path.join(this.dists, chanDebs.channel, 'Release.gpg'); - const inReleaseFilePath = path.join(this.dists, chanDebs.channel, 'InRelease'); + const releasePath = path.join(this.dists, channel, 'main', `binary-${ arch }`, 'Release'); + const releaseFilePath = path.join(this.dists, channel, 'Release'); + const releaseGpgFilePath = path.join(this.dists, channel, 'Release.gpg'); + const inReleaseFilePath = path.join(this.dists, channel, 'InRelease'); - await fs.promises.writeFile(releasePath, releaseContent); - await fs.promises.copyFile(releasePath, releaseFilePath); + await fs.promises.writeFile(releasePath, releaseContent); + await fs.promises.copyFile(releasePath, releaseFilePath); - await this.execToolToFile('apt-ftparchive', ['release', `${ this.dists }/${ chanDebs.channel }`], releaseFilePath, true); - await this.execToolToFile('gpg', ['--default-key', this.config.debBuilder.gpgKeyName, '-abs', '-o', releaseGpgFilePath, releaseFilePath]); - await this.execToolToFile('gpg', ['--default-key', this.config.debBuilder.gpgKeyName, '--clearsign', '-o', inReleaseFilePath, releaseFilePath]); - } + await this.execToolToFile('apt-ftparchive', ['release', `${ this.dists }/${ channel }`], releaseFilePath, true); + await this.execToolToFile('gpg', ['--default-key', this.config.debBuilder.gpgKeyName, '-abs', '-o', releaseGpgFilePath, releaseFilePath]); + await this.execToolToFile('gpg', ['--default-key', this.config.debBuilder.gpgKeyName, '--clearsign', '-o', inReleaseFilePath, releaseFilePath]); } private async execToolToFile(tool: string, args: string[], outputPath?: string, append?: boolean): Promise { From 445e2c755206b480f6470ac1c6123b694a1c03a3 Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Wed, 17 May 2023 16:14:18 +0300 Subject: [PATCH 06/31] lots of linter issues fixed --- .gitignore | 2 + src/artifacts-provider-config.mts | 2 +- src/artifacts-provider.mts | 1 + src/config.mts | 2 +- src/deb/deb-builder-config.mts | 18 ++-- src/deb/deb-builder.mts | 118 +++++++++++++------------ src/fs.mts | 51 +++++------ src/http.mts | 81 +++++++---------- src/ibuilder.mts | 8 +- src/index.mts | 11 ++- src/jfrog/jfrog-artifacts-provider.mts | 40 +++++---- src/repo.mts | 12 +-- 12 files changed, 174 insertions(+), 172 deletions(-) diff --git a/.gitignore b/.gitignore index af489f5..37044d1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ out/ # coverage report directory /coverage/ + +jewel-case.config.mjs diff --git a/src/artifacts-provider-config.mts b/src/artifacts-provider-config.mts index 50edcf1..e0284c4 100644 --- a/src/artifacts-provider-config.mts +++ b/src/artifacts-provider-config.mts @@ -9,4 +9,4 @@ export interface ArtifactsProviderConfig { apiKey: string, user: string } -} \ No newline at end of file +} diff --git a/src/artifacts-provider.mts b/src/artifacts-provider.mts index 295f449..4905c98 100644 --- a/src/artifacts-provider.mts +++ b/src/artifacts-provider.mts @@ -10,4 +10,5 @@ export interface Artifact { export interface ArtifactsProvider { artifactsByBuildNumber(buildNumber: string): Promise; artifactUrl(artifact: Artifact): Promise; + createMetapointerFile(artifact: Artifact, fileName: string): void; } diff --git a/src/config.mts b/src/config.mts index 6354ace..306ece1 100644 --- a/src/config.mts +++ b/src/config.mts @@ -1,8 +1,8 @@ import path from 'path'; import { pathToFileURL } from 'url'; -import type { DebBuilderConfig } from './deb/deb-builder-config.mjs'; import type { ArtifactsProviderConfig } from './artifacts-provider-config.mjs'; +import type { DebBuilderConfig } from './deb/deb-builder-config.mjs'; import type { Repo } from './repo.mjs'; interface BaseConfig { diff --git a/src/deb/deb-builder-config.mts b/src/deb/deb-builder-config.mts index 62a9d13..05369b7 100644 --- a/src/deb/deb-builder-config.mts +++ b/src/deb/deb-builder-config.mts @@ -1,9 +1,9 @@ -export interface DebBuilderConfig { - debBuilder: { - gpgPublicKeyPath: string; - gpgKeyName: string; - applicationName: string; - component: string; - origin: string; - } -} +export interface DebBuilderConfig { + debBuilder: { + gpgPublicKeyPath: string; + gpgKeyName: string; + applicationName: string; + component: string; + origin: string; + } +} diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index e61b5a7..44cb30b 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -1,18 +1,20 @@ +import { createGzip } from 'zlib'; +import { spawnSync } from 'child_process'; + +import * as crypto from 'crypto'; +import * as fs from 'fs'; +import * as ini from 'ini'; +import * as os from 'os'; +import * as path from 'path'; +import * as tar from 'tar'; + import type { Artifact, ArtifactsProvider } from '../artifacts-provider.mjs'; import { createDir, removeDir } from '../fs.mjs'; +import type { Config } from '../config.mjs'; import type { IBuilder } from '../ibuilder.mjs'; import { requestRange } from '../http.mjs'; -import type { Config } from '../config.mjs'; -import * as path from 'path'; -import * as fs from 'fs'; -import * as tar from 'tar'; -import * as ini from 'ini'; -import * as crypto from 'crypto'; -import * as os from 'os'; -import { createGzip } from 'zlib'; -import { spawnSync } from 'child_process'; -const ReleaseFileTemplate = +const ReleaseFileTemplate = `Origin: $ORIGIN Label: Ubuntu/Debian Architecture: $ARCH @@ -25,8 +27,8 @@ export class DebBuilder implements IBuilder { private readonly artifactsProvider: ArtifactsProvider; private readonly pool: string; - private readonly dists: string; - private readonly keys: string; + private readonly dists: string; + private readonly keys: string; private debRepo: { channel: string, @@ -39,16 +41,15 @@ export class DebBuilder implements IBuilder { constructor(artifactsProvider: ArtifactsProvider, config: Config) { this.config = config; - this.pool = `${ this.config.base.out }/repo/${ this.config.debBuilder.applicationName }/deb/pool`; - this.dists = `${ this.config.base.out }/repo/${ this.config.debBuilder.applicationName }/deb/dists`; - this.keys = `${ this.config.base.out }/repo/${ this.config.debBuilder.applicationName }/deb/keys`; - this.keys; + this.pool = `${this.config.base.out}/repo/${this.config.debBuilder.applicationName}/deb/pool`; + this.dists = `${this.config.base.out}/repo/${this.config.debBuilder.applicationName}/deb/dists`; + this.keys = `${this.config.base.out}/repo/${this.config.debBuilder.applicationName}/deb/keys`; this.artifactsProvider = artifactsProvider; } public async plan(): Promise { for (const entry of this.config.base.repo) { - let debs: { + const debs: { version: string, url: string, artifact: Artifact @@ -61,7 +62,7 @@ export class DebBuilder implements IBuilder { debs.push({ version: pack.version, url: await this.artifactsProvider.artifactUrl(artifact), - artifact: artifact + artifact, }); } } @@ -69,35 +70,39 @@ export class DebBuilder implements IBuilder { this.debRepo.push({ channel: entry.channel, debs }); } - + for (const channel of this.debRepo) { for (const deb of channel.debs) { const debUrl = deb.url; const controlTarSizeRange = '120-129'; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call - const cocntrolTarSize = Number((await requestRange(debUrl, controlTarSizeRange)).read().toString().trim()); - const controlTarRange = `132-${ 131 + cocntrolTarSize }`; + const cocntrolTarSize = Number((await requestRange(debUrl, controlTarSizeRange)).read().toString() + .trim()); + const controlTarRange = `132-${131 + cocntrolTarSize}`; const controlTar = await requestRange(debUrl, controlTarRange); - const whereExtract = path.join(os.tmpdir(), `control-${ crypto.randomBytes(4).toString('hex')}`); + const whereExtract = path.join(os.tmpdir(), `control-${crypto.randomBytes(4).toString('hex')}`); createDir(whereExtract); - await new Promise((resolve) => { + await new Promise(resolve => { controlTar .pipe(tar.extract({ cwd: whereExtract, strip: 1 }, ['./control'])) .on('finish', () => { const controlMetaContent = fs.readFileSync(path.join(whereExtract, 'control'), 'utf-8').replaceAll(':', '='); const controlMeta = ini.parse(controlMetaContent); - const targetMetaPath = path.join(this.dists, channel.channel, this.config.debBuilder.component, `binary-${ controlMeta['Architecture'] }`, `${ this.debName(deb.version, controlMeta['Architecture']) }.meta`); + const targetMetaPath = path.join(this.dists, channel.channel, this.config.debBuilder.component, `binary-${controlMeta['Architecture']}`, `${this.debName(deb.version, controlMeta['Architecture'])}.meta`); createDir(path.dirname(targetMetaPath)); fs.renameSync(path.join(whereExtract, 'control'), targetMetaPath); removeDir(whereExtract); - const fileName = path.relative(`${ this.config.base.out }/repo/${ this.config.debBuilder.applicationName }/deb`, path.join(this.pool, this.config.debBuilder.component, `${ this.config.debBuilder.applicationName[0]}/${ this.config.debBuilder.applicationName}-${ channel.channel }`, this.debName(deb.version, controlMeta['Architecture']))); + const debPath = path.join(this.pool, this.config.debBuilder.component, `${this.config.debBuilder.applicationName[0]}`, this.config.debBuilder.applicationName, channel.channel, this.debName(deb.version, controlMeta['Architecture'])); + const repoRoot = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb'); + const relativeDebPath = path.relative(repoRoot, debPath); + this.artifactsProvider.createMetapointerFile(deb.artifact, debPath); const debSize = controlTar.headers['content-range']?.split('/')[1]; const sha1 = controlTar.headers['x-checksum-sha1']; const sha256 = controlTar.headers['x-checksum-sha256']; @@ -107,32 +112,31 @@ export class DebBuilder implements IBuilder { throw new Error('No checksum was found in headers'); } - const dataToAppend = `Filename: ${ fileName }\nSize: ${ debSize }\nSHA1: ${ sha1 }\nSHA256: ${ sha256 }\nMD5Sum: ${ md5 }\n`; + const dataToAppend = `Filename: ${relativeDebPath}\nSize: ${debSize}\nSHA1: ${sha1}\nSHA256: ${sha256}\nMD5Sum: ${md5}\n`; - fs.appendFile(targetMetaPath, dataToAppend, (err) => { - if (err) { + fs.appendFile(targetMetaPath, dataToAppend, err => { + if (err) { throw err; } resolve(); }); - }); + }); }); } } - const compressFile = async (input: string): Promise => { - return new Promise((resolve) => { - const inp = fs.createReadStream(input); - const out = fs.createWriteStream(`${ input }.gz`); - - const gzip = createGzip({ level: 9 }); - - inp.pipe(gzip).pipe(out).on('finish', () => { + const compressFile = (input: string): Promise => new Promise(resolve => { + const inp = fs.createReadStream(input); + const out = fs.createWriteStream(`${input}.gz`); + + const gzip = createGzip({ level: 9 }); + + inp.pipe(gzip).pipe(out) + .on('finish', () => { resolve(); }); - }); - } + }); for (const chan of this.debRepo) { const distsRoot = path.join(this.dists, chan.channel, this.config.debBuilder.component); @@ -143,7 +147,7 @@ export class DebBuilder implements IBuilder { const metaFiles = fs.readdirSync(dist) .filter(fileName => fileName.endsWith('.meta')) .map(metaFile => path.join(dist, metaFile)); - + let packagesContent = ''; for (const metaFile of metaFiles) { @@ -162,15 +166,15 @@ export class DebBuilder implements IBuilder { } public apply(): void { - + console.log(this); } private debName(version: string, arch: string): string { - return `${ this.config.debBuilder.applicationName }-${ version }_${ arch }.deb`; + return `${this.config.debBuilder.applicationName}-${version}_${arch}.deb`; } private async makeRelease(channel: string, arch: string): Promise { - console.log('DebBuilder: makeRelease'); + console.log('DebBuilder: makeRelease'); const publicKeyPath = path.join(this.keys, 'desktop.asc'); createDir(this.keys); @@ -182,7 +186,7 @@ export class DebBuilder implements IBuilder { .replace('$ARCH', arch) .replace('$COMPONENT', this.config.debBuilder.component); - const releasePath = path.join(this.dists, channel, 'main', `binary-${ arch }`, 'Release'); + const releasePath = path.join(this.dists, channel, 'main', `binary-${arch}`, 'Release'); const releaseFilePath = path.join(this.dists, channel, 'Release'); const releaseGpgFilePath = path.join(this.dists, channel, 'Release.gpg'); const inReleaseFilePath = path.join(this.dists, channel, 'InRelease'); @@ -190,41 +194,41 @@ export class DebBuilder implements IBuilder { await fs.promises.writeFile(releasePath, releaseContent); await fs.promises.copyFile(releasePath, releaseFilePath); - await this.execToolToFile('apt-ftparchive', ['release', `${ this.dists }/${ channel }`], releaseFilePath, true); + await this.execToolToFile('apt-ftparchive', ['release', `${this.dists}/${channel}`], releaseFilePath, true); await this.execToolToFile('gpg', ['--default-key', this.config.debBuilder.gpgKeyName, '-abs', '-o', releaseGpgFilePath, releaseFilePath]); await this.execToolToFile('gpg', ['--default-key', this.config.debBuilder.gpgKeyName, '--clearsign', '-o', inReleaseFilePath, releaseFilePath]); - } + } private async execToolToFile(tool: string, args: string[], outputPath?: string, append?: boolean): Promise { if (!append && outputPath && fs.existsSync(outputPath)) { await fs.promises.unlink(outputPath); } - - const toolProcessResult = spawnSync(tool, args, {stdio: 'pipe', encoding: 'utf-8'}); + + const toolProcessResult = spawnSync(tool, args, { stdio: 'pipe', encoding: 'utf-8' }); const toolOutput = toolProcessResult.stdout; - + const dumpToolOutput = (): void => { const toolErrOutput = toolProcessResult.stderr; if (toolOutput && toolOutput.length > 0) { console.log(toolOutput); } + if (toolErrOutput && toolErrOutput.length > 0) { console.warn(toolErrOutput); } }; - + if (outputPath) { console.log(`Execute ${tool} ${args.join(' ')} => ${outputPath}`); dumpToolOutput(); if (append) { return fs.promises.appendFile(outputPath, toolOutput); } - - return fs.promises.writeFile(outputPath, toolOutput); - } - else { - console.log(`Execute ${tool} ${args.join(' ')}`); - dumpToolOutput(); + + return fs.promises.writeFile(outputPath, toolOutput); } - } + + console.log(`Execute ${tool} ${args.join(' ')}`); + dumpToolOutput(); + } } diff --git a/src/fs.mts b/src/fs.mts index 615639c..23949b9 100644 --- a/src/fs.mts +++ b/src/fs.mts @@ -1,25 +1,26 @@ -import { writeFileSync, mkdirSync, existsSync, rmdirSync } from 'fs'; - -export function createFile(path: string, content: string): void { - const dirPath = path.split('/').slice(0, -1).join('/'); - - createDir(dirPath); - - writeFileSync(path, content); -} - -export function createDir(dirName: string): void { - if (!existsSync(dirName)) { - mkdirSync(dirName, { recursive: true }); - } -} - -export function removeDir(dirName: string): void { - if (existsSync(dirName)) { - rmdirSync(dirName, {recursive: true}); - } -} - -export function createMetapointerContent(fileMd5Hash: string): string { - return `#metapointer jfrogart\noid md5:${fileMd5Hash}`; -} \ No newline at end of file +import * as path from 'path'; +import { existsSync, mkdirSync, rmdirSync, writeFileSync } from 'fs'; + +export function createFile(filePath: string, content: string): void { + const dirPath = path.dirname(filePath); + + createDir(dirPath); + + writeFileSync(filePath, content); +} + +export function createDir(dirName: string): void { + if (!existsSync(dirName)) { + mkdirSync(dirName, { recursive: true }); + } +} + +export function removeDir(dirName: string): void { + if (existsSync(dirName)) { + rmdirSync(dirName, { recursive: true }); + } +} + +export function createMetapointerContent(fileMd5Hash: string): string { + return `#metapointer jfrogart\noid md5:${fileMd5Hash}`; +} diff --git a/src/http.mts b/src/http.mts index 66eab04..6db22ab 100644 --- a/src/http.mts +++ b/src/http.mts @@ -1,6 +1,6 @@ -import { Readable } from 'stream'; import { request as httpRequest } from 'https'; import type { IncomingMessage } from 'http'; +import { Readable } from 'stream'; export interface RequestBody { content: string | Buffer; @@ -13,82 +13,69 @@ export interface RequestData { redirectHandler?: (url: string) => string | undefined; } -export async function requestStream(url: string, method: string, requestData?: RequestData): Promise { +export function requestStream(url: string, method: string, requestData?: RequestData): Promise { return new Promise((resolve, reject) => { try { const req = httpRequest(url, { method }); - + req .on('response', (incomingMessage: IncomingMessage) => { - if (incomingMessage.statusCode === 301) { - if (incomingMessage.headers.location) { - return requestStream(incomingMessage.headers.location, method, requestData); - } - } - if (incomingMessage.statusCode !== 200) { const stCode = incomingMessage.statusCode ?? 'NO_CODE'; const stMessage = incomingMessage.statusMessage ?? 'NO_MESSAGE'; const message = `[${method} ${url}]:${stCode}/${stMessage}`; reject(new Error(message)); - return; } resolve(incomingMessage); - return; }) .on('error', (err: Error) => { const errno = (err as {errno?: string}).errno ?? ''; if (errno === 'ETIMEDOUT') { reject(new Error(`Request (${url}) timeout.`)); - } - else { + } else { reject(err); } }); - if (requestData) { - if (requestData.headers) { - for (const key of Object.getOwnPropertyNames(requestData.headers)) { - const value = requestData.headers[key]; + if (requestData?.headers) { + for (const key of Object.getOwnPropertyNames(requestData.headers)) { + const value = requestData.headers[key]; - if (value) { - req.setHeader(key, value); - } + if (value) { + req.setHeader(key, value); } } + } - if (requestData.body) { - if (requestData.body.contentType) { - req.setHeader('Content-Type', requestData.body.contentType); - } - req.write(requestData.body.content); + if (requestData?.body) { + if (requestData.body.contentType) { + req.setHeader('Content-Type', requestData.body.contentType); } + req.write(requestData.body.content); } req.end(); - } - catch (err) { + } catch (err) { reject(err); } }); } export async function request(url: string, method: string, requestData?: RequestData): Promise { - const responseStream = await requestStream(url, method, requestData); - let buffer: Buffer | undefined; + let buffer: Buffer | undefined = undefined; for await (const item of responseStream) { const chunk = item as Buffer; - buffer = (typeof buffer === 'undefined') ? chunk : Buffer.concat([buffer, chunk ]); + buffer = (typeof buffer === 'undefined') ? chunk : Buffer.concat([buffer, chunk]); } return buffer ? buffer : Buffer.from(''); } -export async function requestRange(url: string, range: string): Promise { +export function requestRange(url: string, range: string): Promise { return new Promise((resolve, reject) => { try { const req = httpRequest(url, { method: 'GET' }); @@ -109,34 +96,32 @@ export async function requestRange(url: string, range: string): Promise { - const errno = (err as {errno?: string}).errno ?? ''; - if (errno === 'ETIMEDOUT') { - reject(new Error(`Request (${url}) timeout.`)); - } - else { - reject(err); - } - }); + .on('error', (err: Error) => { + const errno = (err as {errno?: string}).errno ?? ''; + if (errno === 'ETIMEDOUT') { + reject(new Error(`Request (${url}) timeout.`)); + } else { + reject(err); + } + }); - req.setHeader('Range', `bytes=${ range }`); + req.setHeader('Range', `bytes=${range}`); req.end(); - } - catch (err) { + } catch (err) { reject(err); } }); } -export function get(url: string, opt?: {stream: false} ): Promise; -export function get(url: string, opt?: {stream: true} ): Promise; +export function get(url: string, opt?: {stream: false}): Promise; +export function get(url: string, opt?: {stream: true}): Promise; -export async function get(url: string, opt: {stream: boolean} = {stream: false}): Promise { - return opt.stream ? requestStream(url, 'GET', undefined ) : request(url, 'GET', undefined ); +export function get(url: string, opt: {stream: boolean} = { stream: false }): Promise { + return opt.stream ? requestStream(url, 'GET', undefined) : request(url, 'GET', undefined); } export function post(url: string, requestData?: RequestData): Promise { - return request(url, 'POST', requestData ); + return request(url, 'POST', requestData); } diff --git a/src/ibuilder.mts b/src/ibuilder.mts index 3e1a283..3437aa5 100644 --- a/src/ibuilder.mts +++ b/src/ibuilder.mts @@ -1,4 +1,4 @@ -export interface IBuilder { - plan(): Promise; - apply(): void; -} +export interface IBuilder { + plan(): Promise; + apply(): void; +} diff --git a/src/index.mts b/src/index.mts index 2a43588..4814120 100644 --- a/src/index.mts +++ b/src/index.mts @@ -1,15 +1,15 @@ import type { Config } from './config.mjs'; +import { DebBuilder } from './deb/deb-builder.mjs'; import type { IBuilder } from './ibuilder.mjs'; import { JfrogArtifactsProvider } from './jfrog/jfrog-artifacts-provider.mjs'; -import { DebBuilder } from './deb/deb-builder.mjs'; -export { type Config, createConfigProvider } from './config.mjs'; +export { type Config, createConfigProvider } from './config.mjs'; export async function plan(config: Config): Promise { const artifactsProvider = new JfrogArtifactsProvider(config); - let builders: IBuilder[] = []; - + const builders: IBuilder[] = []; + if (config.debBuilder) { builders.push(new DebBuilder(artifactsProvider, config)); } @@ -21,7 +21,6 @@ export async function plan(config: Config): Promise { console.log('plan()'); } -export function apply(config: Config): void { - config; +export function apply(): void { console.log('apply()'); } diff --git a/src/jfrog/jfrog-artifacts-provider.mts b/src/jfrog/jfrog-artifacts-provider.mts index 5023f3d..a4daf08 100644 --- a/src/jfrog/jfrog-artifacts-provider.mts +++ b/src/jfrog/jfrog-artifacts-provider.mts @@ -1,6 +1,8 @@ -import { type ArtifactoryClient, createArtifactoryClient, type ArtifactoryItemMeta } from 's3-groundskeeper'; +import { type ArtifactoryClient, type ArtifactoryItemMeta, createArtifactoryClient } from 's3-groundskeeper'; +import { createFile } from '../fs.mjs'; import { get } from '../http.mjs'; + import type { Artifact, ArtifactsProvider } from '../artifacts-provider.mjs'; import type { ArtifactsProviderConfig } from '../artifacts-provider-config.mjs'; @@ -19,6 +21,10 @@ export interface BuildInfo { } } +function metapointerContent(fileMd5Hash: string): string { + return `#metapointer jfrogart\noid md5:${fileMd5Hash}`; +} + export class JfrogArtifactsProvider implements ArtifactsProvider { private artifactoryClient: ArtifactoryClient; private buildsList?: BuildsList; @@ -26,12 +32,12 @@ export class JfrogArtifactsProvider implements ArtifactsProvider { private readonly config: ArtifactsProviderConfig; constructor(config: ArtifactsProviderConfig) { - this.config = config; + this.config = config; this.artifactoryClient = createArtifactoryClient({ protocol: this.config.artifactsProvider.protocol, host: this.config.artifactsProvider.host, - apiKey: this.config.artifactsProvider.apiKey, - user: this.config.artifactsProvider.user + apiKey: this.config.artifactsProvider.apiKey, + user: this.config.artifactsProvider.user, }); } @@ -50,24 +56,28 @@ export class JfrogArtifactsProvider implements ArtifactsProvider { public async artifactUrl(artifact: Artifact): Promise { const aqlItemField = 'actual_md5'; - + const artQueryResult = await this.artifactoryClient.query(`items.find({"${aqlItemField}": "${artifact.md5}"}).include("*")`); if (artQueryResult.results.length === 0) { throw new Error(`No artifactory item found for ("${aqlItemField}": "${artifact.md5}"}`); - } - else if (artQueryResult.results.length > 1) { + } else if (artQueryResult.results.length > 1) { throw new Error(`Expected single artifactory item for ("${aqlItemField}": "${artifact.md5}"}`); } - + const item = artQueryResult.results[0]; - + if (!item) { throw new Error(`No artifactory item found for ("${aqlItemField}": "${artifact.md5}"}`); } - + return this.artifactoryClient.resolveUri(item); } + // eslint-disable-next-line class-methods-use-this + public createMetapointerFile(artifact: Artifact, fileName: string): void { + createFile(fileName, metapointerContent(artifact.md5)); + } + private async buildInfosByNumber(buildNumber: string): Promise { if (!this.artifactoryClient) { throw new Error('Artifactory client does not exists'); @@ -75,7 +85,7 @@ export class JfrogArtifactsProvider implements ArtifactsProvider { const result: BuildInfo[] = []; - const buildsEndpoint = this.artifactoryClient.resolveUri(`api/build/${ this.config.artifactsProvider.project }`);; + const buildsEndpoint = this.artifactoryClient.resolveUri(`api/build/${this.config.artifactsProvider.project}`); if (!this.buildsList) { const allBuilds = await get(buildsEndpoint); @@ -84,18 +94,18 @@ export class JfrogArtifactsProvider implements ArtifactsProvider { const buildTimes = (buildUri: string): Date[] => { const times: Date[] = []; - + this.buildsList?.buildsNumbers.forEach(build => { - if (build.uri === `/${ buildUri}`) { + if (build.uri === `/${buildUri}`) { times.push(new Date(build.started)); } }); - + return times; }; for (const value of buildTimes(buildNumber)) { - const buildInfoEndpoint = `${ buildsEndpoint }/${ buildNumber }?started=${ value.toISOString() }`; + const buildInfoEndpoint = `${buildsEndpoint}/${buildNumber}?started=${value.toISOString()}`; const info = (await get(buildInfoEndpoint)).toString(); const buildInfo = JSON.parse(info) as BuildInfo; diff --git a/src/repo.mts b/src/repo.mts index 6fca0fb..74225a6 100644 --- a/src/repo.mts +++ b/src/repo.mts @@ -1,15 +1,15 @@ export interface Package { - version: string, - buildNumber: string + version: string, + buildNumber: string } export interface Packages { - packages: Package[], - highest: Package, + packages: Package[], + highest: Package, } export type Channel = string; export type Repo = { - channel: Channel, - packages: Packages + channel: Channel, + packages: Packages }[] From ceabe0cbcf7dbf62f61e11bd53048ba6c36b8194 Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Fri, 19 May 2023 15:34:29 +0300 Subject: [PATCH 07/31] refactoring: removing awaits from loops --- src/cli.mts | 2 +- src/deb/deb-builder.mts | 208 +++++++++++++++---------- src/index.mts | 8 +- src/jfrog/jfrog-artifacts-provider.mts | 12 +- 4 files changed, 141 insertions(+), 89 deletions(-) diff --git a/src/cli.mts b/src/cli.mts index e63a4b0..1952798 100644 --- a/src/cli.mts +++ b/src/cli.mts @@ -22,7 +22,7 @@ async function main(): Promise { } if (command === 'apply') { - apply(configProvider.config); + apply(); } return 0; diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index 44cb30b..42376fe 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -13,6 +13,7 @@ import { createDir, removeDir } from '../fs.mjs'; import type { Config } from '../config.mjs'; import type { IBuilder } from '../ibuilder.mjs'; import { requestRange } from '../http.mjs'; +import type { Packages } from '../repo.mjs'; const ReleaseFileTemplate = `Origin: $ORIGIN @@ -21,6 +22,11 @@ Architecture: $ARCH Component: $COMPONENT Codename: $CHANNEL\n`; +interface DebDescriptor { + version: string, + url: string, + artifact: Artifact +} export class DebBuilder implements IBuilder { private readonly config: Config; @@ -32,11 +38,8 @@ export class DebBuilder implements IBuilder { private debRepo: { channel: string, - debs: { - version: string, - url: string, - artifact: Artifact - }[]}[] = []; + debs: DebDescriptor[] + }[] = []; constructor(artifactsProvider: ArtifactsProvider, config: Config) { this.config = config; @@ -48,83 +51,8 @@ export class DebBuilder implements IBuilder { } public async plan(): Promise { - for (const entry of this.config.base.repo) { - const debs: { - version: string, - url: string, - artifact: Artifact - }[] = []; - - for (const pack of entry.packages.packages) { - const debArtifactItems = (await this.artifactsProvider.artifactsByBuildNumber(pack.buildNumber)).filter(artifact => artifact.type === 'deb'); - - for (const artifact of debArtifactItems) { - debs.push({ - version: pack.version, - url: await this.artifactsProvider.artifactUrl(artifact), - artifact, - }); - } - } - - this.debRepo.push({ channel: entry.channel, debs }); - } - - - for (const channel of this.debRepo) { - for (const deb of channel.debs) { - const debUrl = deb.url; - const controlTarSizeRange = '120-129'; - - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call - const cocntrolTarSize = Number((await requestRange(debUrl, controlTarSizeRange)).read().toString() - .trim()); - const controlTarRange = `132-${131 + cocntrolTarSize}`; - const controlTar = await requestRange(debUrl, controlTarRange); - - const whereExtract = path.join(os.tmpdir(), `control-${crypto.randomBytes(4).toString('hex')}`); - - createDir(whereExtract); - - await new Promise(resolve => { - controlTar - .pipe(tar.extract({ cwd: whereExtract, strip: 1 }, ['./control'])) - .on('finish', () => { - const controlMetaContent = fs.readFileSync(path.join(whereExtract, 'control'), 'utf-8').replaceAll(':', '='); - const controlMeta = ini.parse(controlMetaContent); - - const targetMetaPath = path.join(this.dists, channel.channel, this.config.debBuilder.component, `binary-${controlMeta['Architecture']}`, `${this.debName(deb.version, controlMeta['Architecture'])}.meta`); - createDir(path.dirname(targetMetaPath)); - fs.renameSync(path.join(whereExtract, 'control'), targetMetaPath); - - removeDir(whereExtract); - - const debPath = path.join(this.pool, this.config.debBuilder.component, `${this.config.debBuilder.applicationName[0]}`, this.config.debBuilder.applicationName, channel.channel, this.debName(deb.version, controlMeta['Architecture'])); - const repoRoot = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb'); - const relativeDebPath = path.relative(repoRoot, debPath); - this.artifactsProvider.createMetapointerFile(deb.artifact, debPath); - const debSize = controlTar.headers['content-range']?.split('/')[1]; - const sha1 = controlTar.headers['x-checksum-sha1']; - const sha256 = controlTar.headers['x-checksum-sha256']; - const md5 = controlTar.headers['x-checksum-md5']; - - if (typeof sha1 !== 'string' || typeof sha256 !== 'string' || typeof md5 !== 'string' || typeof debSize !== 'string') { - throw new Error('No checksum was found in headers'); - } - - const dataToAppend = `Filename: ${relativeDebPath}\nSize: ${debSize}\nSHA1: ${sha1}\nSHA256: ${sha256}\nMD5Sum: ${md5}\n`; - - fs.appendFile(targetMetaPath, dataToAppend, err => { - if (err) { - throw err; - } - - resolve(); - }); - }); - }); - } - } + await this.prepareMetaRepository(); + await this.dpkgScanpackages(); const compressFile = (input: string): Promise => new Promise(resolve => { const inp = fs.createReadStream(input); @@ -199,6 +127,122 @@ export class DebBuilder implements IBuilder { await this.execToolToFile('gpg', ['--default-key', this.config.debBuilder.gpgKeyName, '--clearsign', '-o', inReleaseFilePath, releaseFilePath]); } + private async prepareMetaRepository(): Promise { + const debsPromises: Promise<{channel: string, debs: DebDescriptor[]}>[] = []; + + this.config.base.repo.forEach(channelEntry => { + const a = (async (): Promise<{ channel: string, debs: DebDescriptor[] }> => { + return { + channel: channelEntry.channel, + debs: await this.debsByPackages(channelEntry.packages) + }; + })(); + + debsPromises.push(a); + }); + + const b = await Promise.all(debsPromises); + + b.forEach(entry => { + this.debRepo.push(entry); + }); + } + + private async debsByPackages(packs: Packages): Promise { + const debsPromises: Promise[] = []; + const artsByBuildNumbersPromises: Promise<{version: string, artifacts: Artifact[]}>[] = []; + + packs.packages.forEach(pack => { + artsByBuildNumbersPromises.push((async (): Promise<{ version: string, artifacts: Artifact[] }> => { + return { + version: pack.version, + artifacts: await this.artifactsProvider.artifactsByBuildNumber(pack.buildNumber), + }; + })()); + }); + + const artsByBuildNumbers = await Promise.all(artsByBuildNumbersPromises); + + artsByBuildNumbers.forEach(value => { + value.artifacts.filter(artifact => artifact.type === 'deb').forEach(artifact => { + debsPromises.push((async (): Promise => { + return { + version: value.version, + artifact: artifact, + url: await this.artifactsProvider.artifactUrl(artifact) + }; + })()); + }) + }); + + return Promise.all(debsPromises); + } + + private async dpkgScanpackages(): Promise { + const promises: Promise[] = []; + + this.debRepo.forEach(channel => { + channel.debs.forEach(deb => { + promises.push(this.handleDeb(channel.channel, deb)); + }); + }); + + await Promise.all(promises); + } + + private async handleDeb(channel: string, deb: DebDescriptor): Promise { + const debUrl = deb.url; + const controlTarSizeRange = '120-129'; + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call + const cocntrolTarSize = Number((await requestRange(debUrl, controlTarSizeRange)).read().toString() + .trim()); + const controlTarRange = `132-${131 + cocntrolTarSize}`; + const controlTar = await requestRange(debUrl, controlTarRange); + + const whereExtract = path.join(os.tmpdir(), `control-${crypto.randomBytes(4).toString('hex')}`); + + createDir(whereExtract); + + await new Promise(resolve => { + controlTar + .pipe(tar.extract({ cwd: whereExtract, strip: 1 }, ['./control'])) + .on('finish', () => { + const controlMetaContent = fs.readFileSync(path.join(whereExtract, 'control'), 'utf-8').replaceAll(':', '='); + const controlMeta = ini.parse(controlMetaContent); + + const targetMetaPath = path.join(this.dists, channel, this.config.debBuilder.component, `binary-${controlMeta['Architecture']}`, `${this.debName(deb.version, controlMeta['Architecture'])}.meta`); + createDir(path.dirname(targetMetaPath)); + fs.renameSync(path.join(whereExtract, 'control'), targetMetaPath); + + removeDir(whereExtract); + + const debPath = path.join(this.pool, this.config.debBuilder.component, `${this.config.debBuilder.applicationName[0]}`, this.config.debBuilder.applicationName, channel, this.debName(deb.version, controlMeta['Architecture'])); + const repoRoot = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb'); + const relativeDebPath = path.relative(repoRoot, debPath); + this.artifactsProvider.createMetapointerFile(deb.artifact, debPath); + const debSize = controlTar.headers['content-range']?.split('/')[1]; + const sha1 = controlTar.headers['x-checksum-sha1']; + const sha256 = controlTar.headers['x-checksum-sha256']; + const md5 = controlTar.headers['x-checksum-md5']; + + if (typeof sha1 !== 'string' || typeof sha256 !== 'string' || typeof md5 !== 'string' || typeof debSize !== 'string') { + throw new Error('No checksum was found in headers'); + } + + const dataToAppend = `Filename: ${relativeDebPath}\nSize: ${debSize}\nSHA1: ${sha1}\nSHA256: ${sha256}\nMD5Sum: ${md5}\n`; + + fs.appendFile(targetMetaPath, dataToAppend, err => { + if (err) { + throw err; + } + + resolve(); + }); + }); + }); + } + private async execToolToFile(tool: string, args: string[], outputPath?: string, append?: boolean): Promise { if (!append && outputPath && fs.existsSync(outputPath)) { await fs.promises.unlink(outputPath); diff --git a/src/index.mts b/src/index.mts index 4814120..89b9d13 100644 --- a/src/index.mts +++ b/src/index.mts @@ -5,7 +5,7 @@ import { JfrogArtifactsProvider } from './jfrog/jfrog-artifacts-provider.mjs'; export { type Config, createConfigProvider } from './config.mjs'; -export async function plan(config: Config): Promise { +export function plan(config: Config): Promise { const artifactsProvider = new JfrogArtifactsProvider(config); const builders: IBuilder[] = []; @@ -14,11 +14,13 @@ export async function plan(config: Config): Promise { builders.push(new DebBuilder(artifactsProvider, config)); } + const planPromises: Promise[] = []; + for (const builder of builders) { - await builder.plan(); + planPromises.push(builder.plan()); } - console.log('plan()'); + return Promise.all(planPromises); } export function apply(): void { diff --git a/src/jfrog/jfrog-artifacts-provider.mts b/src/jfrog/jfrog-artifacts-provider.mts index a4daf08..91dd65b 100644 --- a/src/jfrog/jfrog-artifacts-provider.mts +++ b/src/jfrog/jfrog-artifacts-provider.mts @@ -104,13 +104,19 @@ export class JfrogArtifactsProvider implements ArtifactsProvider { return times; }; + const infoPromises: Promise[] = []; + for (const value of buildTimes(buildNumber)) { const buildInfoEndpoint = `${buildsEndpoint}/${buildNumber}?started=${value.toISOString()}`; - const info = (await get(buildInfoEndpoint)).toString(); - const buildInfo = JSON.parse(info) as BuildInfo; + infoPromises.push(get(buildInfoEndpoint)); + } + + const infos = await Promise.all(infoPromises); + infos.forEach(info => { + const buildInfo = JSON.parse(info.toString()) as BuildInfo; result.push(buildInfo); - } + }); return result; } From 67c678cc530fc4d7c488fcb9e47c0032a57abb84 Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Fri, 19 May 2023 17:18:42 +0300 Subject: [PATCH 08/31] refactor: linter fix --- src/deb/deb-builder.mts | 194 +++++++++++++++++++--------------------- src/fs.mts | 39 +++++++- src/http.mts | 2 + 3 files changed, 134 insertions(+), 101 deletions(-) diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index 42376fe..db6fa56 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -1,5 +1,4 @@ import { createGzip } from 'zlib'; -import { spawnSync } from 'child_process'; import * as crypto from 'crypto'; import * as fs from 'fs'; @@ -9,11 +8,11 @@ import * as path from 'path'; import * as tar from 'tar'; import type { Artifact, ArtifactsProvider } from '../artifacts-provider.mjs'; -import { createDir, removeDir } from '../fs.mjs'; +import { createDir, execToolToFile, removeDir } from '../fs.mjs'; import type { Config } from '../config.mjs'; import type { IBuilder } from '../ibuilder.mjs'; -import { requestRange } from '../http.mjs'; import type { Packages } from '../repo.mjs'; +import { requestRange } from '../http.mjs'; const ReleaseFileTemplate = `Origin: $ORIGIN @@ -41,6 +40,8 @@ export class DebBuilder implements IBuilder { debs: DebDescriptor[] }[] = []; + private archesByChannel: Map> = new Map(); + constructor(artifactsProvider: ArtifactsProvider, config: Config) { this.config = config; @@ -53,44 +54,7 @@ export class DebBuilder implements IBuilder { public async plan(): Promise { await this.prepareMetaRepository(); await this.dpkgScanpackages(); - - const compressFile = (input: string): Promise => new Promise(resolve => { - const inp = fs.createReadStream(input); - const out = fs.createWriteStream(`${input}.gz`); - - const gzip = createGzip({ level: 9 }); - - inp.pipe(gzip).pipe(out) - .on('finish', () => { - resolve(); - }); - }); - - for (const chan of this.debRepo) { - const distsRoot = path.join(this.dists, chan.channel, this.config.debBuilder.component); - const distsByArch = fs.readdirSync(distsRoot).map(dist => path.join(distsRoot, dist)); - - for (const dist of distsByArch) { - const targetPackagesFile = path.join(dist, 'Packages'); - const metaFiles = fs.readdirSync(dist) - .filter(fileName => fileName.endsWith('.meta')) - .map(metaFile => path.join(dist, metaFile)); - - let packagesContent = ''; - - for (const metaFile of metaFiles) { - packagesContent += fs.readFileSync(metaFile); - packagesContent += '\n'; - fs.unlinkSync(metaFile); - } - - fs.writeFileSync(targetPackagesFile, packagesContent); - - await compressFile(targetPackagesFile); - } - - await this.makeRelease(chan.channel, 'amd64'); - } + await this.makeRelease(); } public apply(): void { @@ -101,9 +65,7 @@ export class DebBuilder implements IBuilder { return `${this.config.debBuilder.applicationName}-${version}_${arch}.deb`; } - private async makeRelease(channel: string, arch: string): Promise { - console.log('DebBuilder: makeRelease'); - + private async makeReleaseFileAndSign(channel: string, arch: string): Promise { const publicKeyPath = path.join(this.keys, 'desktop.asc'); createDir(this.keys); await fs.promises.copyFile(this.config.debBuilder.gpgPublicKeyPath, publicKeyPath); @@ -114,36 +76,31 @@ export class DebBuilder implements IBuilder { .replace('$ARCH', arch) .replace('$COMPONENT', this.config.debBuilder.component); - const releasePath = path.join(this.dists, channel, 'main', `binary-${arch}`, 'Release'); const releaseFilePath = path.join(this.dists, channel, 'Release'); const releaseGpgFilePath = path.join(this.dists, channel, 'Release.gpg'); const inReleaseFilePath = path.join(this.dists, channel, 'InRelease'); - await fs.promises.writeFile(releasePath, releaseContent); - await fs.promises.copyFile(releasePath, releaseFilePath); + await fs.promises.writeFile(releaseFilePath, releaseContent); + await fs.promises.copyFile(releaseFilePath, inReleaseFilePath); - await this.execToolToFile('apt-ftparchive', ['release', `${this.dists}/${channel}`], releaseFilePath, true); - await this.execToolToFile('gpg', ['--default-key', this.config.debBuilder.gpgKeyName, '-abs', '-o', releaseGpgFilePath, releaseFilePath]); - await this.execToolToFile('gpg', ['--default-key', this.config.debBuilder.gpgKeyName, '--clearsign', '-o', inReleaseFilePath, releaseFilePath]); + await execToolToFile('apt-ftparchive', ['release', `${this.dists}/${channel}`], releaseFilePath, true); + await execToolToFile('gpg', ['--default-key', this.config.debBuilder.gpgKeyName, '-abs', '-o', releaseGpgFilePath, releaseFilePath]); + await execToolToFile('gpg', ['--default-key', this.config.debBuilder.gpgKeyName, '--clearsign', '-o', inReleaseFilePath, releaseFilePath]); } private async prepareMetaRepository(): Promise { const debsPromises: Promise<{channel: string, debs: DebDescriptor[]}>[] = []; this.config.base.repo.forEach(channelEntry => { - const a = (async (): Promise<{ channel: string, debs: DebDescriptor[] }> => { - return { - channel: channelEntry.channel, - debs: await this.debsByPackages(channelEntry.packages) - }; - })(); - - debsPromises.push(a); + debsPromises.push((async(): Promise<{ channel: string, debs: DebDescriptor[] }> => ({ + channel: channelEntry.channel, + debs: await this.debsByPackages(channelEntry.packages), + }))()); }); - const b = await Promise.all(debsPromises); + const debs = await Promise.all(debsPromises); - b.forEach(entry => { + debs.forEach(entry => { this.debRepo.push(entry); }); } @@ -153,26 +110,22 @@ export class DebBuilder implements IBuilder { const artsByBuildNumbersPromises: Promise<{version: string, artifacts: Artifact[]}>[] = []; packs.packages.forEach(pack => { - artsByBuildNumbersPromises.push((async (): Promise<{ version: string, artifacts: Artifact[] }> => { - return { - version: pack.version, - artifacts: await this.artifactsProvider.artifactsByBuildNumber(pack.buildNumber), - }; - })()); + artsByBuildNumbersPromises.push((async(): Promise<{ version: string, artifacts: Artifact[] }> => ({ + version: pack.version, + artifacts: await this.artifactsProvider.artifactsByBuildNumber(pack.buildNumber), + }))()); }); const artsByBuildNumbers = await Promise.all(artsByBuildNumbersPromises); artsByBuildNumbers.forEach(value => { value.artifacts.filter(artifact => artifact.type === 'deb').forEach(artifact => { - debsPromises.push((async (): Promise => { - return { - version: value.version, - artifact: artifact, - url: await this.artifactsProvider.artifactUrl(artifact) - }; - })()); - }) + debsPromises.push((async(): Promise => ({ + version: value.version, + artifact, + url: await this.artifactsProvider.artifactUrl(artifact), + }))()); + }); }); return Promise.all(debsPromises); @@ -207,17 +160,36 @@ export class DebBuilder implements IBuilder { await new Promise(resolve => { controlTar .pipe(tar.extract({ cwd: whereExtract, strip: 1 }, ['./control'])) + // eslint-disable-next-line max-statements .on('finish', () => { const controlMetaContent = fs.readFileSync(path.join(whereExtract, 'control'), 'utf-8').replaceAll(':', '='); const controlMeta = ini.parse(controlMetaContent); + const arch = controlMeta['Architecture']; - const targetMetaPath = path.join(this.dists, channel, this.config.debBuilder.component, `binary-${controlMeta['Architecture']}`, `${this.debName(deb.version, controlMeta['Architecture'])}.meta`); + const archesSet = this.archesByChannel.get(channel); + + if (archesSet) { + archesSet.add(arch); + } else { + this.archesByChannel.set(channel, new Set([arch])); + } + + const targetMetaPath = path.join(this.dists, + channel, + this.config.debBuilder.component, + `binary-${arch}`, + `${this.debName(deb.version, arch)}.meta`); createDir(path.dirname(targetMetaPath)); fs.renameSync(path.join(whereExtract, 'control'), targetMetaPath); removeDir(whereExtract); - const debPath = path.join(this.pool, this.config.debBuilder.component, `${this.config.debBuilder.applicationName[0]}`, this.config.debBuilder.applicationName, channel, this.debName(deb.version, controlMeta['Architecture'])); + const debPath = path.join(this.pool, + this.config.debBuilder.component, + `${this.config.debBuilder.applicationName[0]}`, + this.config.debBuilder.applicationName, + channel, + this.debName(deb.version, arch)); const repoRoot = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb'); const relativeDebPath = path.relative(repoRoot, debPath); this.artifactsProvider.createMetapointerFile(deb.artifact, debPath); @@ -243,36 +215,58 @@ export class DebBuilder implements IBuilder { }); } - private async execToolToFile(tool: string, args: string[], outputPath?: string, append?: boolean): Promise { - if (!append && outputPath && fs.existsSync(outputPath)) { - await fs.promises.unlink(outputPath); - } + private async makeRelease(): Promise<{}> { + const compressFile = (filePath: string): Promise => new Promise(resolve => { + const inp = fs.createReadStream(filePath); + const out = fs.createWriteStream(`${filePath}.gz`); - const toolProcessResult = spawnSync(tool, args, { stdio: 'pipe', encoding: 'utf-8' }); - const toolOutput = toolProcessResult.stdout; + const gzip = createGzip({ level: 9 }); - const dumpToolOutput = (): void => { - const toolErrOutput = toolProcessResult.stderr; - if (toolOutput && toolOutput.length > 0) { - console.log(toolOutput); - } + inp.pipe(gzip).pipe(out) + .on('finish', () => { + resolve(); + }); + }); - if (toolErrOutput && toolErrOutput.length > 0) { - console.warn(toolErrOutput); - } - }; + const compressPromises: Promise[] = []; + + this.debRepo.forEach(channelEntry => { + const distsRoot = path.join(this.dists, channelEntry.channel, this.config.debBuilder.component); + const distsByArch = fs.readdirSync(distsRoot).map(dist => path.join(distsRoot, dist)); + + distsByArch.forEach(dist => { + const targetPackagesFile = path.join(dist, 'Packages'); + const metaFiles = fs.readdirSync(dist) + .filter(fileName => fileName.endsWith('.meta')) + .map(metaFile => path.join(dist, metaFile)); + + let packagesContent = ''; + + for (const metaFile of metaFiles) { + packagesContent += fs.readFileSync(metaFile); + packagesContent += '\n'; + fs.unlinkSync(metaFile); + } - if (outputPath) { - console.log(`Execute ${tool} ${args.join(' ')} => ${outputPath}`); - dumpToolOutput(); - if (append) { - return fs.promises.appendFile(outputPath, toolOutput); + fs.writeFileSync(targetPackagesFile, packagesContent); + + compressPromises.push(compressFile(targetPackagesFile)); + }); + }); + + await Promise.all(compressPromises); + + const releasesPromises: Promise[] = []; + + this.debRepo.forEach(chan => { + const archesSet = this.archesByChannel.get(chan.channel); + if (!archesSet) { + throw new Error('No arch was found for channel'); } - return fs.promises.writeFile(outputPath, toolOutput); - } + releasesPromises.push(this.makeReleaseFileAndSign(chan.channel, [...archesSet.values()].join(' '))); + }); - console.log(`Execute ${tool} ${args.join(' ')}`); - dumpToolOutput(); + return Promise.all(releasesPromises); } } diff --git a/src/fs.mts b/src/fs.mts index 23949b9..a2363b4 100644 --- a/src/fs.mts +++ b/src/fs.mts @@ -1,5 +1,6 @@ import * as path from 'path'; -import { existsSync, mkdirSync, rmdirSync, writeFileSync } from 'fs'; +import { existsSync, promises as fsPromises, mkdirSync, rmdirSync, writeFileSync } from 'fs'; +import { spawnSync } from 'child_process'; export function createFile(filePath: string, content: string): void { const dirPath = path.dirname(filePath); @@ -24,3 +25,39 @@ export function removeDir(dirName: string): void { export function createMetapointerContent(fileMd5Hash: string): string { return `#metapointer jfrogart\noid md5:${fileMd5Hash}`; } + +// eslint-disable-next-line max-params +export async function execToolToFile(tool: string, args: string[], outputPath?: string, append?: boolean): Promise { + if (!append && outputPath && existsSync(outputPath)) { + await fsPromises.unlink(outputPath); + } + + const toolProcessResult = spawnSync(tool, args, { stdio: 'pipe', encoding: 'utf-8' }); + const toolOutput = toolProcessResult.stdout; + + const dumpToolOutput = (): void => { + const toolErrOutput = toolProcessResult.stderr; + if (toolOutput && toolOutput.length > 0) { + console.log(toolOutput); + } + + if (toolErrOutput && toolErrOutput.length > 0) { + console.warn(toolErrOutput); + } + }; + + if (outputPath) { + console.log(`Execute ${tool} ${args.join(' ')} => ${outputPath}`); + dumpToolOutput(); + if (append) { + return fsPromises.appendFile(outputPath, toolOutput); + } + + return fsPromises.writeFile(outputPath, toolOutput); + } + + console.log(`Execute ${tool} ${args.join(' ')}`); + dumpToolOutput(); + + return Promise.resolve(); +} diff --git a/src/http.mts b/src/http.mts index 6db22ab..db51764 100644 --- a/src/http.mts +++ b/src/http.mts @@ -116,8 +116,10 @@ export function requestRange(url: string, range: string): Promise; +// eslint-disable-next-line no-redeclare export function get(url: string, opt?: {stream: true}): Promise; +// eslint-disable-next-line no-redeclare export function get(url: string, opt: {stream: boolean} = { stream: false }): Promise { return opt.stream ? requestStream(url, 'GET', undefined) : request(url, 'GET', undefined); } From 459cb9c0326be0cc433278a939d9efc0e137c13b Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Fri, 19 May 2023 17:52:33 +0300 Subject: [PATCH 09/31] use --no-tty for gpg --- src/deb/deb-builder.mts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index db6fa56..38f7b20 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -81,11 +81,10 @@ export class DebBuilder implements IBuilder { const inReleaseFilePath = path.join(this.dists, channel, 'InRelease'); await fs.promises.writeFile(releaseFilePath, releaseContent); - await fs.promises.copyFile(releaseFilePath, inReleaseFilePath); await execToolToFile('apt-ftparchive', ['release', `${this.dists}/${channel}`], releaseFilePath, true); - await execToolToFile('gpg', ['--default-key', this.config.debBuilder.gpgKeyName, '-abs', '-o', releaseGpgFilePath, releaseFilePath]); - await execToolToFile('gpg', ['--default-key', this.config.debBuilder.gpgKeyName, '--clearsign', '-o', inReleaseFilePath, releaseFilePath]); + await execToolToFile('gpg', ['--no-tty', '--default-key', this.config.debBuilder.gpgKeyName, '-abs', '-o', releaseGpgFilePath, releaseFilePath]); + await execToolToFile('gpg', ['--no-tty', '--default-key', this.config.debBuilder.gpgKeyName, '--clearsign', '-o', inReleaseFilePath, releaseFilePath]); } private async prepareMetaRepository(): Promise { From 624f2466f58b1d5327e2fbc64c6e4a273651ef22 Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Wed, 5 Jul 2023 12:27:18 +0300 Subject: [PATCH 10/31] review notes fix --- src/deb/deb-builder.mts | 20 ++++++++++--------- src/{ibuilder.mts => deployer.mts} | 2 +- src/http.mts | 10 ++-------- src/index.mts | 6 +++--- ...ts-provider.mts => artifacts-provider.mts} | 16 +++++++-------- src/s3-metapointer.mts | 3 +++ 6 files changed, 27 insertions(+), 30 deletions(-) rename src/{ibuilder.mts => deployer.mts} (60%) rename src/jfrog/{jfrog-artifacts-provider.mts => artifacts-provider.mts} (89%) create mode 100644 src/s3-metapointer.mts diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index 38f7b20..715b50a 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -10,7 +10,7 @@ import * as tar from 'tar'; import type { Artifact, ArtifactsProvider } from '../artifacts-provider.mjs'; import { createDir, execToolToFile, removeDir } from '../fs.mjs'; import type { Config } from '../config.mjs'; -import type { IBuilder } from '../ibuilder.mjs'; +import type { Deployer } from '../deployer.mjs'; import type { Packages } from '../repo.mjs'; import { requestRange } from '../http.mjs'; @@ -27,7 +27,12 @@ interface DebDescriptor { artifact: Artifact } -export class DebBuilder implements IBuilder { +interface ChannelItem { + channel: string; + debs: DebDescriptor[] +} + +export class DebBuilder implements Deployer { private readonly config: Config; private readonly artifactsProvider: ArtifactsProvider; @@ -35,19 +40,16 @@ export class DebBuilder implements IBuilder { private readonly dists: string; private readonly keys: string; - private debRepo: { - channel: string, - debs: DebDescriptor[] - }[] = []; + private debRepo: ChannelItem[] = []; private archesByChannel: Map> = new Map(); constructor(artifactsProvider: ArtifactsProvider, config: Config) { this.config = config; - this.pool = `${this.config.base.out}/repo/${this.config.debBuilder.applicationName}/deb/pool`; - this.dists = `${this.config.base.out}/repo/${this.config.debBuilder.applicationName}/deb/dists`; - this.keys = `${this.config.base.out}/repo/${this.config.debBuilder.applicationName}/deb/keys`; + this.pool = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb', 'pool'); + this.dists = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb', 'dists'); + this.keys = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb', 'keys'); this.artifactsProvider = artifactsProvider; } diff --git a/src/ibuilder.mts b/src/deployer.mts similarity index 60% rename from src/ibuilder.mts rename to src/deployer.mts index 3437aa5..b98939a 100644 --- a/src/ibuilder.mts +++ b/src/deployer.mts @@ -1,4 +1,4 @@ -export interface IBuilder { +export interface Deployer { plan(): Promise; apply(): void; } diff --git a/src/http.mts b/src/http.mts index db51764..ba35c16 100644 --- a/src/http.mts +++ b/src/http.mts @@ -1,6 +1,5 @@ import { request as httpRequest } from 'https'; import type { IncomingMessage } from 'http'; -import { Readable } from 'stream'; export interface RequestBody { content: string | Buffer; @@ -115,13 +114,8 @@ export function requestRange(url: string, range: string): Promise; -// eslint-disable-next-line no-redeclare -export function get(url: string, opt?: {stream: true}): Promise; - -// eslint-disable-next-line no-redeclare -export function get(url: string, opt: {stream: boolean} = { stream: false }): Promise { - return opt.stream ? requestStream(url, 'GET', undefined) : request(url, 'GET', undefined); +export function get(url: string): Promise { + return request(url, 'GET', undefined); } export function post(url: string, requestData?: RequestData): Promise { diff --git a/src/index.mts b/src/index.mts index 89b9d13..5a40180 100644 --- a/src/index.mts +++ b/src/index.mts @@ -1,14 +1,14 @@ import type { Config } from './config.mjs'; import { DebBuilder } from './deb/deb-builder.mjs'; -import type { IBuilder } from './ibuilder.mjs'; -import { JfrogArtifactsProvider } from './jfrog/jfrog-artifacts-provider.mjs'; +import type { Deployer } from './deployer.mjs'; +import JfrogArtifactsProvider from './jfrog/artifacts-provider.mjs'; export { type Config, createConfigProvider } from './config.mjs'; export function plan(config: Config): Promise { const artifactsProvider = new JfrogArtifactsProvider(config); - const builders: IBuilder[] = []; + const builders: Deployer[] = []; if (config.debBuilder) { builders.push(new DebBuilder(artifactsProvider, config)); diff --git a/src/jfrog/jfrog-artifacts-provider.mts b/src/jfrog/artifacts-provider.mts similarity index 89% rename from src/jfrog/jfrog-artifacts-provider.mts rename to src/jfrog/artifacts-provider.mts index 91dd65b..97df7e5 100644 --- a/src/jfrog/jfrog-artifacts-provider.mts +++ b/src/jfrog/artifacts-provider.mts @@ -5,15 +5,16 @@ import { get } from '../http.mjs'; import type { Artifact, ArtifactsProvider } from '../artifacts-provider.mjs'; import type { ArtifactsProviderConfig } from '../artifacts-provider-config.mjs'; +import metapointerContent from '../s3-metapointer.mjs'; -export interface BuildsList { +interface BuildsList { buildsNumbers: { uri: string, started: string }[] } -export interface BuildInfo { +interface BuildInfo { buildInfo: { modules: { artifacts: Artifact[] @@ -21,11 +22,7 @@ export interface BuildInfo { } } -function metapointerContent(fileMd5Hash: string): string { - return `#metapointer jfrogart\noid md5:${fileMd5Hash}`; -} - -export class JfrogArtifactsProvider implements ArtifactsProvider { +export default class JfrogArtifactsProvider implements ArtifactsProvider { private artifactoryClient: ArtifactoryClient; private buildsList?: BuildsList; @@ -107,8 +104,9 @@ export class JfrogArtifactsProvider implements ArtifactsProvider { const infoPromises: Promise[] = []; for (const value of buildTimes(buildNumber)) { - const buildInfoEndpoint = `${buildsEndpoint}/${buildNumber}?started=${value.toISOString()}`; - infoPromises.push(get(buildInfoEndpoint)); + const buildInfoEndpointUrl = new URL(buildNumber, buildsEndpoint); + buildInfoEndpointUrl.searchParams.set('started', value.toISOString()); + infoPromises.push(get(buildInfoEndpointUrl.toString())); } const infos = await Promise.all(infoPromises); diff --git a/src/s3-metapointer.mts b/src/s3-metapointer.mts new file mode 100644 index 0000000..ce93b26 --- /dev/null +++ b/src/s3-metapointer.mts @@ -0,0 +1,3 @@ +export default function metapointerContent(fileMd5Hash: string): string { + return `#metapointer jfrogart\noid md5:${fileMd5Hash}`; +} From 0e47e628e021bf60d6f6a452bfdbda7ce260ffad Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Wed, 7 Feb 2024 13:30:13 +0300 Subject: [PATCH 11/31] renamed to artifact-provider --- ...der-config.mts => artifact-provider-config.mts} | 2 +- ...rtifacts-provider.mts => artifact-provider.mts} | 2 +- src/config.mts | 4 ++-- src/deb/deb-builder.mts | 14 +++++++------- src/index.mts | 4 ++-- ...rtifacts-provider.mts => artifact-provider.mts} | 10 +++++----- 6 files changed, 18 insertions(+), 18 deletions(-) rename src/{artifacts-provider-config.mts => artifact-provider-config.mts} (80%) rename src/{artifacts-provider.mts => artifact-provider.mts} (89%) rename src/jfrog/{artifacts-provider.mts => artifact-provider.mts} (90%) diff --git a/src/artifacts-provider-config.mts b/src/artifact-provider-config.mts similarity index 80% rename from src/artifacts-provider-config.mts rename to src/artifact-provider-config.mts index e0284c4..52a6212 100644 --- a/src/artifacts-provider-config.mts +++ b/src/artifact-provider-config.mts @@ -1,6 +1,6 @@ export type ProviderType = 'jfrog'; -export interface ArtifactsProviderConfig { +export interface ArtifactProviderConfig { artifactsProvider: { type: ProviderType, protocol: string, diff --git a/src/artifacts-provider.mts b/src/artifact-provider.mts similarity index 89% rename from src/artifacts-provider.mts rename to src/artifact-provider.mts index 4905c98..0babc5b 100644 --- a/src/artifacts-provider.mts +++ b/src/artifact-provider.mts @@ -7,7 +7,7 @@ export interface Artifact { md5: string } -export interface ArtifactsProvider { +export interface ArtifactProvider { artifactsByBuildNumber(buildNumber: string): Promise; artifactUrl(artifact: Artifact): Promise; createMetapointerFile(artifact: Artifact, fileName: string): void; diff --git a/src/config.mts b/src/config.mts index 306ece1..ac68ee9 100644 --- a/src/config.mts +++ b/src/config.mts @@ -1,7 +1,7 @@ import path from 'path'; import { pathToFileURL } from 'url'; -import type { ArtifactsProviderConfig } from './artifacts-provider-config.mjs'; +import type { ArtifactProviderConfig } from './artifact-provider-config.mjs'; import type { DebBuilderConfig } from './deb/deb-builder-config.mjs'; import type { Repo } from './repo.mjs'; @@ -12,7 +12,7 @@ interface BaseConfig { } } -export type Config = BaseConfig & DebBuilderConfig & ArtifactsProviderConfig; +export type Config = BaseConfig & DebBuilderConfig & ArtifactProviderConfig; export class ConfigProvider { private path: string; diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index 715b50a..e3a87a0 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -7,7 +7,7 @@ import * as os from 'os'; import * as path from 'path'; import * as tar from 'tar'; -import type { Artifact, ArtifactsProvider } from '../artifacts-provider.mjs'; +import type { Artifact, ArtifactProvider } from '../artifact-provider.mjs'; import { createDir, execToolToFile, removeDir } from '../fs.mjs'; import type { Config } from '../config.mjs'; import type { Deployer } from '../deployer.mjs'; @@ -34,7 +34,7 @@ interface ChannelItem { export class DebBuilder implements Deployer { private readonly config: Config; - private readonly artifactsProvider: ArtifactsProvider; + private readonly artifactProvider: ArtifactProvider; private readonly pool: string; private readonly dists: string; @@ -44,13 +44,13 @@ export class DebBuilder implements Deployer { private archesByChannel: Map> = new Map(); - constructor(artifactsProvider: ArtifactsProvider, config: Config) { + constructor(artifactProvider: ArtifactProvider, config: Config) { this.config = config; this.pool = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb', 'pool'); this.dists = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb', 'dists'); this.keys = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb', 'keys'); - this.artifactsProvider = artifactsProvider; + this.artifactProvider = artifactProvider; } public async plan(): Promise { @@ -113,7 +113,7 @@ export class DebBuilder implements Deployer { packs.packages.forEach(pack => { artsByBuildNumbersPromises.push((async(): Promise<{ version: string, artifacts: Artifact[] }> => ({ version: pack.version, - artifacts: await this.artifactsProvider.artifactsByBuildNumber(pack.buildNumber), + artifacts: await this.artifactProvider.artifactsByBuildNumber(pack.buildNumber), }))()); }); @@ -124,7 +124,7 @@ export class DebBuilder implements Deployer { debsPromises.push((async(): Promise => ({ version: value.version, artifact, - url: await this.artifactsProvider.artifactUrl(artifact), + url: await this.artifactProvider.artifactUrl(artifact), }))()); }); }); @@ -193,7 +193,7 @@ export class DebBuilder implements Deployer { this.debName(deb.version, arch)); const repoRoot = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb'); const relativeDebPath = path.relative(repoRoot, debPath); - this.artifactsProvider.createMetapointerFile(deb.artifact, debPath); + this.artifactProvider.createMetapointerFile(deb.artifact, debPath); const debSize = controlTar.headers['content-range']?.split('/')[1]; const sha1 = controlTar.headers['x-checksum-sha1']; const sha256 = controlTar.headers['x-checksum-sha256']; diff --git a/src/index.mts b/src/index.mts index 5a40180..65d676c 100644 --- a/src/index.mts +++ b/src/index.mts @@ -1,12 +1,12 @@ import type { Config } from './config.mjs'; import { DebBuilder } from './deb/deb-builder.mjs'; import type { Deployer } from './deployer.mjs'; -import JfrogArtifactsProvider from './jfrog/artifacts-provider.mjs'; +import JfrogArtifactProvider from './jfrog/artifact-provider.mjs'; export { type Config, createConfigProvider } from './config.mjs'; export function plan(config: Config): Promise { - const artifactsProvider = new JfrogArtifactsProvider(config); + const artifactsProvider = new JfrogArtifactProvider(config); const builders: Deployer[] = []; diff --git a/src/jfrog/artifacts-provider.mts b/src/jfrog/artifact-provider.mts similarity index 90% rename from src/jfrog/artifacts-provider.mts rename to src/jfrog/artifact-provider.mts index 97df7e5..d4c57ba 100644 --- a/src/jfrog/artifacts-provider.mts +++ b/src/jfrog/artifact-provider.mts @@ -3,8 +3,8 @@ import { type ArtifactoryClient, type ArtifactoryItemMeta, createArtifactoryClie import { createFile } from '../fs.mjs'; import { get } from '../http.mjs'; -import type { Artifact, ArtifactsProvider } from '../artifacts-provider.mjs'; -import type { ArtifactsProviderConfig } from '../artifacts-provider-config.mjs'; +import type { Artifact, ArtifactProvider } from '../artifact-provider.mjs'; +import type { ArtifactProviderConfig } from '../artifact-provider-config.mjs'; import metapointerContent from '../s3-metapointer.mjs'; interface BuildsList { @@ -22,13 +22,13 @@ interface BuildInfo { } } -export default class JfrogArtifactsProvider implements ArtifactsProvider { +export default class JfrogArtifactProvider implements ArtifactProvider { private artifactoryClient: ArtifactoryClient; private buildsList?: BuildsList; - private readonly config: ArtifactsProviderConfig; + private readonly config: ArtifactProviderConfig; - constructor(config: ArtifactsProviderConfig) { + constructor(config: ArtifactProviderConfig) { this.config = config; this.artifactoryClient = createArtifactoryClient({ protocol: this.config.artifactsProvider.protocol, From fe35c0044940bf964f20a0b0d7651290573da169 Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Wed, 7 Feb 2024 13:35:55 +0300 Subject: [PATCH 12/31] s3-gk moved from dev deps to runtime deps --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0698b01..f13c02c 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "husky": "^8.0.0", "jest": "^29.3.1", "lint-staged": "^13.0.4", - "s3-groundskeeper": "0.2.2", "ts-jest": "^29.1.0", "ts-node": "^10.9.1", "typescript": "^5.0.4" @@ -42,6 +41,7 @@ }, "dependencies": { "ini": "^4.1.0", + "s3-groundskeeper": "0.2.2", "tar": "^6.1.13", "yargs": "^17.6.2" } From 6c3717929d19ee456d8a3fd2476e286143e86259 Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Wed, 7 Feb 2024 14:54:17 +0300 Subject: [PATCH 13/31] discard mixin in config and remade using nested objects --- src/artifact-provider-config.mts | 14 ++++++-------- src/config.mts | 12 +++++++----- src/deb/deb-builder-config.mts | 12 +++++------- src/index.mts | 2 +- src/jfrog/artifact-provider.mts | 10 +++++----- 5 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/artifact-provider-config.mts b/src/artifact-provider-config.mts index 52a6212..aff021e 100644 --- a/src/artifact-provider-config.mts +++ b/src/artifact-provider-config.mts @@ -1,12 +1,10 @@ export type ProviderType = 'jfrog'; export interface ArtifactProviderConfig { - artifactsProvider: { - type: ProviderType, - protocol: string, - host: string, - project: string, - apiKey: string, - user: string - } + type: ProviderType, + protocol: string, + host: string, + project: string, + apiKey: string, + user: string } diff --git a/src/config.mts b/src/config.mts index ac68ee9..8e86587 100644 --- a/src/config.mts +++ b/src/config.mts @@ -6,13 +6,15 @@ import type { DebBuilderConfig } from './deb/deb-builder-config.mjs'; import type { Repo } from './repo.mjs'; interface BaseConfig { - base: { - out: string; - repo: Repo; - } + out: string; + repo: Repo; } -export type Config = BaseConfig & DebBuilderConfig & ArtifactProviderConfig; +export interface Config { + base: BaseConfig; + artifactsProvider: ArtifactProviderConfig; + debBuilder: DebBuilderConfig; +} export class ConfigProvider { private path: string; diff --git a/src/deb/deb-builder-config.mts b/src/deb/deb-builder-config.mts index 05369b7..07e02b3 100644 --- a/src/deb/deb-builder-config.mts +++ b/src/deb/deb-builder-config.mts @@ -1,9 +1,7 @@ export interface DebBuilderConfig { - debBuilder: { - gpgPublicKeyPath: string; - gpgKeyName: string; - applicationName: string; - component: string; - origin: string; - } + gpgPublicKeyPath: string; + gpgKeyName: string; + applicationName: string; + component: string; + origin: string; } diff --git a/src/index.mts b/src/index.mts index 65d676c..4087883 100644 --- a/src/index.mts +++ b/src/index.mts @@ -6,7 +6,7 @@ import JfrogArtifactProvider from './jfrog/artifact-provider.mjs'; export { type Config, createConfigProvider } from './config.mjs'; export function plan(config: Config): Promise { - const artifactsProvider = new JfrogArtifactProvider(config); + const artifactsProvider = new JfrogArtifactProvider(config.artifactsProvider); const builders: Deployer[] = []; diff --git a/src/jfrog/artifact-provider.mts b/src/jfrog/artifact-provider.mts index d4c57ba..ce55cd9 100644 --- a/src/jfrog/artifact-provider.mts +++ b/src/jfrog/artifact-provider.mts @@ -31,10 +31,10 @@ export default class JfrogArtifactProvider implements ArtifactProvider { constructor(config: ArtifactProviderConfig) { this.config = config; this.artifactoryClient = createArtifactoryClient({ - protocol: this.config.artifactsProvider.protocol, - host: this.config.artifactsProvider.host, - apiKey: this.config.artifactsProvider.apiKey, - user: this.config.artifactsProvider.user, + protocol: this.config.protocol, + host: this.config.host, + apiKey: this.config.apiKey, + user: this.config.user, }); } @@ -82,7 +82,7 @@ export default class JfrogArtifactProvider implements ArtifactProvider { const result: BuildInfo[] = []; - const buildsEndpoint = this.artifactoryClient.resolveUri(`api/build/${this.config.artifactsProvider.project}`); + const buildsEndpoint = this.artifactoryClient.resolveUri(`api/build/${this.config.project}`); if (!this.buildsList) { const allBuilds = await get(buildsEndpoint); From 6db3ea11ef30d2cfba5c71a10aaf935f7eda7fb0 Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Wed, 7 Feb 2024 15:04:46 +0300 Subject: [PATCH 14/31] store prepeared repository root path for reuse --- src/deb/deb-builder.mts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index e3a87a0..0139185 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -36,6 +36,7 @@ export class DebBuilder implements Deployer { private readonly config: Config; private readonly artifactProvider: ArtifactProvider; + private readonly root: string; private readonly pool: string; private readonly dists: string; private readonly keys: string; @@ -47,9 +48,10 @@ export class DebBuilder implements Deployer { constructor(artifactProvider: ArtifactProvider, config: Config) { this.config = config; - this.pool = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb', 'pool'); - this.dists = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb', 'dists'); - this.keys = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb', 'keys'); + this.root = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb'); + this.pool = path.join(this.root, 'pool'); + this.dists = path.join(this.root, 'dists'); + this.keys = path.join(this.root, 'keys'); this.artifactProvider = artifactProvider; } @@ -191,8 +193,7 @@ export class DebBuilder implements Deployer { this.config.debBuilder.applicationName, channel, this.debName(deb.version, arch)); - const repoRoot = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb'); - const relativeDebPath = path.relative(repoRoot, debPath); + const relativeDebPath = path.relative(this.root, debPath); this.artifactProvider.createMetapointerFile(deb.artifact, debPath); const debSize = controlTar.headers['content-range']?.split('/')[1]; const sha1 = controlTar.headers['x-checksum-sha1']; From 4a32567699f9fedc75d75a23b43edcca879cff07 Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Fri, 16 Feb 2024 16:51:39 +0300 Subject: [PATCH 15/31] adjust builder and artifact proviver to new s3gk api --- package.json | 2 +- pnpm-lock.yaml | 213 +++++++++++++++---------------- src/artifact-provider-config.mts | 1 - src/artifact-provider.mts | 6 +- src/deb/deb-builder.mts | 21 ++- src/jfrog/artifact-provider.mts | 40 ++++-- 6 files changed, 145 insertions(+), 138 deletions(-) diff --git a/package.json b/package.json index f13c02c..49e94bf 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ }, "dependencies": { "ini": "^4.1.0", - "s3-groundskeeper": "0.2.2", + "s3-groundskeeper": "0.3.1", "tar": "^6.1.13", "yargs": "^17.6.2" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 54918c6..a56962f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,9 @@ importers: ini: specifier: ^4.1.0 version: 4.1.0 + s3-groundskeeper: + specifier: 0.3.1 + version: 0.3.1 tar: specifier: ^6.1.13 version: 6.1.13 @@ -59,9 +62,6 @@ importers: lint-staged: specifier: ^13.0.4 version: 13.0.4 - s3-groundskeeper: - specifier: 0.2.2 - version: 0.2.2 ts-jest: specifier: ^29.1.0 version: 29.1.0(@babel/core@7.20.5)(jest@29.3.1)(typescript@5.0.4) @@ -94,7 +94,7 @@ packages: '@aws-crypto/util': 3.0.0 '@aws-sdk/types': 3.310.0 tslib: 1.14.1 - dev: true + dev: false /@aws-crypto/crc32c@3.0.0: resolution: {integrity: sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==} @@ -102,13 +102,13 @@ packages: '@aws-crypto/util': 3.0.0 '@aws-sdk/types': 3.310.0 tslib: 1.14.1 - dev: true + dev: false /@aws-crypto/ie11-detection@3.0.0: resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==} dependencies: tslib: 1.14.1 - dev: true + dev: false /@aws-crypto/sha1-browser@3.0.0: resolution: {integrity: sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==} @@ -120,7 +120,7 @@ packages: '@aws-sdk/util-locate-window': 3.310.0 '@aws-sdk/util-utf8-browser': 3.259.0 tslib: 1.14.1 - dev: true + dev: false /@aws-crypto/sha256-browser@3.0.0: resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==} @@ -133,7 +133,7 @@ packages: '@aws-sdk/util-locate-window': 3.310.0 '@aws-sdk/util-utf8-browser': 3.259.0 tslib: 1.14.1 - dev: true + dev: false /@aws-crypto/sha256-js@3.0.0: resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} @@ -141,13 +141,13 @@ packages: '@aws-crypto/util': 3.0.0 '@aws-sdk/types': 3.310.0 tslib: 1.14.1 - dev: true + dev: false /@aws-crypto/supports-web-crypto@3.0.0: resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} dependencies: tslib: 1.14.1 - dev: true + dev: false /@aws-crypto/util@3.0.0: resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} @@ -155,7 +155,7 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-utf8-browser': 3.259.0 tslib: 1.14.1 - dev: true + dev: false /@aws-sdk/abort-controller@3.310.0: resolution: {integrity: sha512-v1zrRQxDLA1MdPim159Vx/CPHqsB4uybSxRi1CnfHO5ZjHryx3a5htW2gdGAykVCul40+yJXvfpufMrELVxH+g==} @@ -163,13 +163,13 @@ packages: dependencies: '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/chunked-blob-reader@3.310.0: resolution: {integrity: sha512-CrJS3exo4mWaLnWxfCH+w88Ou0IcAZSIkk4QbmxiHl/5Dq705OLoxf4385MVyExpqpeVJYOYQ2WaD8i/pQZ2fg==} dependencies: tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/client-s3@3.315.0: resolution: {integrity: sha512-sE2pCFNrhkn1XdqkHx1GEd4eKg/kITk2zHETpkQCUMAVZ1MDuY/uUZzRjbAn9sm9EsJ03Z/vOuK4DkxlLFY+8g==} @@ -232,7 +232,7 @@ packages: transitivePeerDependencies: - '@aws-sdk/signature-v4-crt' - aws-crt - dev: true + dev: false /@aws-sdk/client-sso-oidc@3.315.0: resolution: {integrity: sha512-OJgtmx6SpCWHBDCxBBi36Ro44uCqZBufGkThP/PVYrgVnRVnJ4V18d2wNGKmS37zKmCHHJPnhMPlGOgE2qyVPQ==} @@ -272,7 +272,7 @@ packages: tslib: 2.5.0 transitivePeerDependencies: - aws-crt - dev: true + dev: false /@aws-sdk/client-sso@3.315.0: resolution: {integrity: sha512-P3QOOyHQER7EDVCzXOsAaJE2p/qfdsSFsYv8k2S8LqEKGH0fViQ4Ph540uKlmaOt1kEhwH1wI6cLRMJJX9XV4Q==} @@ -312,7 +312,7 @@ packages: tslib: 2.5.0 transitivePeerDependencies: - aws-crt - dev: true + dev: false /@aws-sdk/client-sts@3.315.0: resolution: {integrity: sha512-e34plg6m0hScADIPiu5kCKoiJVXRLRiAuens+iwMse0oPUmrv41hdjgufwWGA/pcNkEGzMdVS88Z4khxB3LHBw==} @@ -356,7 +356,7 @@ packages: tslib: 2.5.0 transitivePeerDependencies: - aws-crt - dev: true + dev: false /@aws-sdk/config-resolver@3.310.0: resolution: {integrity: sha512-8vsT+/50lOqfDxka9m/rRt6oxv1WuGZoP8oPMk0Dt+TxXMbAzf4+rejBgiB96wshI1k3gLokYRjSQZn+dDtT8g==} @@ -366,7 +366,7 @@ packages: '@aws-sdk/util-config-provider': 3.310.0 '@aws-sdk/util-middleware': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/credential-provider-env@3.310.0: resolution: {integrity: sha512-vvIPQpI16fj95xwS7M3D48F7QhZJBnnCgB5lR+b7So+vsG9ibm1mZRVGzVpdxCvgyOhHFbvrby9aalNJmmIP1A==} @@ -375,7 +375,7 @@ packages: '@aws-sdk/property-provider': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/credential-provider-imds@3.310.0: resolution: {integrity: sha512-baxK7Zp6dai5AGW01FIW27xS2KAaPUmKLIXv5SvFYsUgXXvNW55im4uG3b+2gA0F7V+hXvVBH08OEqmwW6we5w==} @@ -386,7 +386,7 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/url-parser': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/credential-provider-ini@3.315.0: resolution: {integrity: sha512-TZbYNbQkNgANx3KsWmJEyBsnfUBq/XKqYYc/VQf1L4eI+GMUw2eKpNV0MTsyviViy2st7W4SiSgtsvXyeVp9xg==} @@ -403,7 +403,7 @@ packages: tslib: 2.5.0 transitivePeerDependencies: - aws-crt - dev: true + dev: false /@aws-sdk/credential-provider-node@3.315.0: resolution: {integrity: sha512-OuzKAIg+xPAzBrb/Big5VKDpJmBhVR+N0Hfflrjj2BunQGWO7zxtkKFCz921MtP9ZunDV+UxzTpar8U5TAPtzA==} @@ -421,7 +421,7 @@ packages: tslib: 2.5.0 transitivePeerDependencies: - aws-crt - dev: true + dev: false /@aws-sdk/credential-provider-process@3.310.0: resolution: {integrity: sha512-h73sg6GPMUWC+3zMCbA1nZ2O03nNJt7G96JdmnantiXBwHpRKWW8nBTLzx5uhXn6hTuTaoQRP/P+oxQJKYdMmA==} @@ -431,7 +431,7 @@ packages: '@aws-sdk/shared-ini-file-loader': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/credential-provider-sso@3.315.0: resolution: {integrity: sha512-oMDGwT67cLgLiLEj5UwAiOVo7mb0l4vi2nk+5pgPMpC3cBlAfA0y1IJe4FHp+Vz52F0nvURZZbdWhX6RgMMaqQ==} @@ -445,7 +445,7 @@ packages: tslib: 2.5.0 transitivePeerDependencies: - aws-crt - dev: true + dev: false /@aws-sdk/credential-provider-web-identity@3.310.0: resolution: {integrity: sha512-H4SzuZXILNhK6/IR1uVvsUDZvzc051hem7GLyYghBCu8mU+tq28YhKE8MfSroi6eL2e5Vujloij1OM2EQQkPkw==} @@ -454,7 +454,7 @@ packages: '@aws-sdk/property-provider': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/eventstream-codec@3.310.0: resolution: {integrity: sha512-clIeSgWbZbxwtsxZ/yoedNM0/kJFSIjjHPikuDGhxhqc+vP6TN3oYyVMFrYwFaTFhk2+S5wZcWYMw8Op1pWo+A==} @@ -463,7 +463,7 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-hex-encoding': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/eventstream-serde-browser@3.310.0: resolution: {integrity: sha512-3S6ziuQVALgEyz0TANGtYDVeG8ArK4Y05mcgrs8qUTmsvlDIXX37cR/DvmVbNB76M4IrsZeSAIajL9644CywkA==} @@ -472,7 +472,7 @@ packages: '@aws-sdk/eventstream-serde-universal': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/eventstream-serde-config-resolver@3.310.0: resolution: {integrity: sha512-8s1Qdn9STj+sV75nUp9yt0W6fHS4BZ2jTm4Z/1Pcbvh2Gqs0WjH5n2StS+pDW5Y9J/HSGBl0ogmUr5lC5bXFHg==} @@ -480,7 +480,7 @@ packages: dependencies: '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/eventstream-serde-node@3.310.0: resolution: {integrity: sha512-kSnRomCgW43K9TmQYuwN9+AoYPnhyOKroanUMyZEzJk7rpCPMj4OzaUpXfDYOvznFNYn7NLaH6nHLJAr0VPlJA==} @@ -489,7 +489,7 @@ packages: '@aws-sdk/eventstream-serde-universal': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/eventstream-serde-universal@3.310.0: resolution: {integrity: sha512-Qyjt5k/waV5cDukpgT824ISZAz5U0pwzLz5ztR409u85AGNkF/9n7MS+LSyBUBSb0WJ5pUeSD47WBk+nLq9Nhw==} @@ -498,7 +498,7 @@ packages: '@aws-sdk/eventstream-codec': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/fetch-http-handler@3.310.0: resolution: {integrity: sha512-Bi9vIwzdkw1zMcvi/zGzlWS9KfIEnAq4NNhsnCxbQ4OoIRU9wvU+WGZdBBhxg0ZxZmpp1j1aZhU53lLjA07MHw==} @@ -508,7 +508,7 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-base64': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/hash-blob-browser@3.310.0: resolution: {integrity: sha512-OoR8p0cbypToysLT0v3o2oyjy6+DKrY7GNCAzHOHJK9xmqXCt+DsjKoPeiY7o1sWX2aN6Plmvubj/zWxMKEn/A==} @@ -516,7 +516,7 @@ packages: '@aws-sdk/chunked-blob-reader': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/hash-node@3.310.0: resolution: {integrity: sha512-NvE2fhRc8GRwCXBfDehxVAWCmVwVMILliAKVPAEr4yz2CkYs0tqU51S48x23dtna07H4qHtgpeNqVTthcIQOEQ==} @@ -526,7 +526,7 @@ packages: '@aws-sdk/util-buffer-from': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/hash-stream-node@3.310.0: resolution: {integrity: sha512-ZoXdybNgvMz1Hl6k/e32xVL3jmG5p2IEk5mTtLfFEuskTJ74Z+VMYKkkF1whyy7KQfH83H+TQGnsGtlRCchQKw==} @@ -535,21 +535,21 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/invalid-dependency@3.310.0: resolution: {integrity: sha512-1s5RG5rSPXoa/aZ/Kqr5U/7lqpx+Ry81GprQ2bxWqJvWQIJ0IRUwo5pk8XFxbKVr/2a+4lZT/c3OGoBOM1yRRA==} dependencies: '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/is-array-buffer@3.310.0: resolution: {integrity: sha512-urnbcCR+h9NWUnmOtet/s4ghvzsidFmspfhYaHAmSRdy9yDjdjBJMFjjsn85A1ODUktztm+cVncXjQ38WCMjMQ==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/md5-js@3.310.0: resolution: {integrity: sha512-x5sRBUrEfLWAS1EhwbbDQ7cXq6uvBxh3qR2XAsnGvFFceTeAadk7cVogWxlk3PC+OCeeym7c3/6Bv2HQ2f1YyQ==} @@ -557,7 +557,7 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-bucket-endpoint@3.310.0: resolution: {integrity: sha512-uJJfHI7v4AgbJZRLtyI8ap2QRWkBokGc3iyUoQ+dVNT3/CE2ZCu694A6W+H0dRqg79dIE+f9CRNdtLGa/Ehhvg==} @@ -568,7 +568,7 @@ packages: '@aws-sdk/util-arn-parser': 3.310.0 '@aws-sdk/util-config-provider': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-content-length@3.310.0: resolution: {integrity: sha512-P8tQZxgDt6CAh1wd/W6WPzjc+uWPJwQkm+F7rAwRlM+k9q17HrhnksGDKcpuuLyIhPQYdmOMIkpKVgXGa4avhQ==} @@ -577,7 +577,7 @@ packages: '@aws-sdk/protocol-http': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-endpoint@3.310.0: resolution: {integrity: sha512-Z+N2vOL8K354/lstkClxLLsr6hCpVRh+0tCMXrVj66/NtKysCEZ/0b9LmqOwD9pWHNiI2mJqXwY0gxNlKAroUg==} @@ -588,7 +588,7 @@ packages: '@aws-sdk/url-parser': 3.310.0 '@aws-sdk/util-middleware': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-expect-continue@3.310.0: resolution: {integrity: sha512-l3d1z2gt+gINJDnPSyu84IxfzjzPfCQrqC1sunw2cZGo/sXtEiq698Q3SiTcO2PGP4LBQAy2RHb5wVBJP708CQ==} @@ -597,7 +597,7 @@ packages: '@aws-sdk/protocol-http': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-flexible-checksums@3.310.0: resolution: {integrity: sha512-5ndnLgzgGVpWkmHBAiYkagHqiSuow8q62J4J6E2PzaQ77+fm8W3nfdy7hK5trHokEyouCZdxT/XK/IRhgj/4PA==} @@ -610,7 +610,7 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-host-header@3.310.0: resolution: {integrity: sha512-QWSA+46/hXorXyWa61ic2K7qZzwHTiwfk2e9mRRjeIRepUgI3qxFjsYqrWtrOGBjmFmq0pYIY8Bb/DCJuQqcoA==} @@ -619,7 +619,7 @@ packages: '@aws-sdk/protocol-http': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-location-constraint@3.310.0: resolution: {integrity: sha512-LFm0JTQWwTPWL/tZU2wsQTl8J5PpDEkXjEhaXVKamtyH0xhysRqd+0n92n65dc8oztAuQkb9xUbErGn5b6gsew==} @@ -627,7 +627,7 @@ packages: dependencies: '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-logger@3.310.0: resolution: {integrity: sha512-Lurm8XofrASBRnAVtiSNuDSRsRqPNg27RIFLLsLp/pqog9nFJ0vz0kgdb9S5Z+zw83Mm+UlqOe6D8NTUNp4fVg==} @@ -635,7 +635,7 @@ packages: dependencies: '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-recursion-detection@3.310.0: resolution: {integrity: sha512-SuB75/xk/gyue24gkriTwO2jFd7YcUGZDClQYuRejgbXSa3CO0lWyawQtfLcSSEBp9izrEVXuFH24K1eAft5nQ==} @@ -644,7 +644,7 @@ packages: '@aws-sdk/protocol-http': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-retry@3.310.0: resolution: {integrity: sha512-oTPsRy2W4s+dfxbJPW7Km+hHtv/OMsNsVfThAq8DDYKC13qlr1aAyOqGLD+dpBy2aKe7ss517Sy2HcHtHqm7/g==} @@ -657,7 +657,7 @@ packages: '@aws-sdk/util-retry': 3.310.0 tslib: 2.5.0 uuid: 8.3.2 - dev: true + dev: false /@aws-sdk/middleware-sdk-s3@3.310.0: resolution: {integrity: sha512-QK9x9g2ksg0hOjjYgqddeFcn5ctUEGdxJVu4OumPXceulefMcSO2jyH2qTybYSA93nqNQFdFmg5wQfvIRUWFCQ==} @@ -667,7 +667,7 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-arn-parser': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-sdk-sts@3.310.0: resolution: {integrity: sha512-+5PFwlYNLvLLIfw0ASAoWV/iIF8Zv6R6QGtyP0CclhRSvNjgbQDVnV0g95MC5qvh+GB/Yjlkt8qAjLSPjHfsrQ==} @@ -676,7 +676,7 @@ packages: '@aws-sdk/middleware-signing': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-serde@3.310.0: resolution: {integrity: sha512-RNeeTVWSLTaentUeCgQKZhAl+C6hxtwD78cQWS10UymWpQFwbaxztzKUu4UQS5xA2j6PxwPRRUjqa4jcFjfLsg==} @@ -684,7 +684,7 @@ packages: dependencies: '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-signing@3.310.0: resolution: {integrity: sha512-f9mKq+XMdW207Af3hKjdTnpNhdtwqWuvFs/ZyXoOkp/g1MY1O6L23Jy6i52m29LxbT4AuNRG1oKODfXM0vYVjQ==} @@ -696,7 +696,7 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-middleware': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-ssec@3.310.0: resolution: {integrity: sha512-CnEwNKVpd5bXnrCKPaePF8mWTA9ET21OMBb54y9b0fd8K02zoOcdBz4DWfh1SjFD4HkgCdja4egd8l2ivyvqmw==} @@ -704,14 +704,14 @@ packages: dependencies: '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-stack@3.310.0: resolution: {integrity: sha512-010O1PD+UAcZVKRvqEusE1KJqN96wwrf6QsqbRM0ywsKQ21NDweaHvEDlds2VHpgmofxkRLRu/IDrlPkKRQrRg==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/middleware-user-agent@3.310.0: resolution: {integrity: sha512-x3IOwSwSbwKidlxRk3CNVHVUb06SRuaELxggCaR++QVI8NU6qD/l4VHXKVRvbTHiC/cYxXE/GaBDgQVpDR7V/g==} @@ -721,7 +721,7 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-endpoints': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/node-config-provider@3.310.0: resolution: {integrity: sha512-T/Pp6htc6hq/Cq+MLNDSyiwWCMVF6GqbBbXKVlO5L8rdHx4sq9xPdoPveZhGWrxvkanjA6eCwUp6E0riBOSVng==} @@ -731,7 +731,7 @@ packages: '@aws-sdk/shared-ini-file-loader': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/node-http-handler@3.310.0: resolution: {integrity: sha512-irv9mbcM9xC2xYjArQF5SYmHBMu4ciMWtGsoHII1nRuFOl9FoT4ffTvEPuLlfC6pznzvKt9zvnm6xXj7gDChKg==} @@ -742,7 +742,7 @@ packages: '@aws-sdk/querystring-builder': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/property-provider@3.310.0: resolution: {integrity: sha512-3lxDb0akV6BBzmFe4nLPaoliQbAifyWJhuvuDOu7e8NzouvpQXs0275w9LePhhcgjKAEVXUIse05ZW2DLbxo/g==} @@ -750,7 +750,7 @@ packages: dependencies: '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/protocol-http@3.310.0: resolution: {integrity: sha512-fgZ1aw/irQtnrsR58pS8ThKOWo57Py3xX6giRvwSgZDEcxHfVzuQjy9yPuV++v04fdmdtgpbGf8WfvAAJ11yXQ==} @@ -758,7 +758,7 @@ packages: dependencies: '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/querystring-builder@3.310.0: resolution: {integrity: sha512-ZHH8GV/80+pWGo7DzsvwvXR5xVxUHXUvPJPFAkhr6nCf78igdoF8gR10ScFoEKbtEapoNTaZlKHPXxpD8aPG7A==} @@ -767,7 +767,7 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-uri-escape': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/querystring-parser@3.310.0: resolution: {integrity: sha512-YkIznoP6lsiIUHinx++/lbb3tlMURGGqMpo0Pnn32zYzGrJXA6eC3D0as2EcMjo55onTfuLcIiX4qzXes2MYOA==} @@ -775,12 +775,12 @@ packages: dependencies: '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/service-error-classification@3.310.0: resolution: {integrity: sha512-PuyC7k3qfIKeH2LCnDwbttMOKq3qAx4buvg0yfnJtQOz6t1AR8gsnAq0CjKXXyfkXwNKWTqCpE6lVNUIkXgsMw==} engines: {node: '>=14.0.0'} - dev: true + dev: false /@aws-sdk/shared-ini-file-loader@3.310.0: resolution: {integrity: sha512-N0q9pG0xSjQwc690YQND5bofm+4nfUviQ/Ppgan2kU6aU0WUq8KwgHJBto/YEEI+VlrME30jZJnxtOvcZJc2XA==} @@ -788,7 +788,7 @@ packages: dependencies: '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/signature-v4-multi-region@3.310.0: resolution: {integrity: sha512-q8W+RIomTS/q85Ntgks/CoDElwqkC9+4OCicee5YznNHjQ4gtNWhUkYIyIRWRmXa/qx/AUreW9DM8FAecCOdng==} @@ -803,7 +803,7 @@ packages: '@aws-sdk/signature-v4': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/signature-v4@3.310.0: resolution: {integrity: sha512-1M60P1ZBNAjCFv9sYW29OF6okktaeibWyW3lMXqzoHF70lHBZh+838iUchznXUA5FLabfn4jBFWMRxlAXJUY2Q==} @@ -816,7 +816,7 @@ packages: '@aws-sdk/util-uri-escape': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/smithy-client@3.315.0: resolution: {integrity: sha512-qTm0lwTh6IZMiWs3U9k2veoF6gV9yE0B9Z34yMxagOfQFQgxMih0aiH25MD25eRigjJ3sfUeZ+B0mRycmJZdkQ==} @@ -825,7 +825,7 @@ packages: '@aws-sdk/middleware-stack': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/token-providers@3.315.0: resolution: {integrity: sha512-EjLUQ9JLqU3eJfJyzpcVjFnuJ1MCCodZaVJmuX/a/as4TK41bKMvkVojjsU7pDSYzl+tuXE+ceivcWK4H0HQdQ==} @@ -838,14 +838,14 @@ packages: tslib: 2.5.0 transitivePeerDependencies: - aws-crt - dev: true + dev: false /@aws-sdk/types@3.310.0: resolution: {integrity: sha512-j8eamQJ7YcIhw7fneUfs8LYl3t01k4uHi4ZDmNRgtbmbmTTG3FZc2MotStZnp3nZB6vLiPF1o5aoJxWVvkzS6A==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/url-parser@3.310.0: resolution: {integrity: sha512-mCLnCaSB9rQvAgx33u0DujLvr4d5yEm/W5r789GblwwQnlNXedVu50QRizMLTpltYWyAUoXjJgQnJHmJMaKXhw==} @@ -853,14 +853,14 @@ packages: '@aws-sdk/querystring-parser': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-arn-parser@3.310.0: resolution: {integrity: sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-base64@3.310.0: resolution: {integrity: sha512-v3+HBKQvqgdzcbL+pFswlx5HQsd9L6ZTlyPVL2LS9nNXnCcR3XgGz9jRskikRUuUvUXtkSG1J88GAOnJ/apTPg==} @@ -868,20 +868,20 @@ packages: dependencies: '@aws-sdk/util-buffer-from': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-body-length-browser@3.310.0: resolution: {integrity: sha512-sxsC3lPBGfpHtNTUoGXMQXLwjmR0zVpx0rSvzTPAuoVILVsp5AU/w5FphNPxD5OVIjNbZv9KsKTuvNTiZjDp9g==} dependencies: tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-body-length-node@3.310.0: resolution: {integrity: sha512-2tqGXdyKhyA6w4zz7UPoS8Ip+7sayOg9BwHNidiGm2ikbDxm1YrCfYXvCBdwaJxa4hJfRVz+aL9e+d3GqPI9pQ==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-buffer-from@3.310.0: resolution: {integrity: sha512-i6LVeXFtGih5Zs8enLrt+ExXY92QV25jtEnTKHsmlFqFAuL3VBeod6boeMXkN2p9lbSVVQ1sAOOYZOHYbYkntw==} @@ -889,14 +889,14 @@ packages: dependencies: '@aws-sdk/is-array-buffer': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-config-provider@3.310.0: resolution: {integrity: sha512-xIBaYo8dwiojCw8vnUcIL4Z5tyfb1v3yjqyJKJWV/dqKUFOOS0U591plmXbM+M/QkXyML3ypon1f8+BoaDExrg==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-defaults-mode-browser@3.315.0: resolution: {integrity: sha512-5cqNvfGos3FB/MHNl+g2fr+tPY7s3k3+96V3wOPWLOksdACth10OxPpHfboXXZDHHkR0hmyJwJcfgA4uQrUcGg==} @@ -906,7 +906,7 @@ packages: '@aws-sdk/types': 3.310.0 bowser: 2.11.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-defaults-mode-node@3.315.0: resolution: {integrity: sha512-vSPIGpzh6NJIMLoh31p7CczSatN46kJdJBrHfODHaIGe4t156x+LfkkcxGQhtifqxglhL7l+fmn5D1fM5exHuA==} @@ -918,7 +918,7 @@ packages: '@aws-sdk/property-provider': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-endpoints@3.310.0: resolution: {integrity: sha512-zG+/d/O5KPmAaeOMPd6bW1abifdT0H03f42keLjYEoRZzYtHPC5DuPE0UayiWGckI6BCDgy0sRKXCYS49UNFaQ==} @@ -926,28 +926,28 @@ packages: dependencies: '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-hex-encoding@3.310.0: resolution: {integrity: sha512-sVN7mcCCDSJ67pI1ZMtk84SKGqyix6/0A1Ab163YKn+lFBQRMKexleZzpYzNGxYzmQS6VanP/cfU7NiLQOaSfA==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-locate-window@3.310.0: resolution: {integrity: sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-middleware@3.310.0: resolution: {integrity: sha512-FTSUKL/eRb9X6uEZClrTe27QFXUNNp7fxYrPndZwk1hlaOP5ix+MIHBcI7pIiiY/JPfOUmPyZOu+HetlFXjWog==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-retry@3.310.0: resolution: {integrity: sha512-FwWGhCBLfoivTMUHu1LIn4NjrN9JLJ/aX5aZmbcPIOhZVFJj638j0qDgZXyfvVqBuBZh7M8kGq0Oahy3dp69OA==} @@ -955,7 +955,7 @@ packages: dependencies: '@aws-sdk/service-error-classification': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-stream-browser@3.310.0: resolution: {integrity: sha512-bysXZHwFwvbqOTCScCdCnoLk1K3GCo0HRIYEZuL7O7MHrQmfaYRXcaft/p22+GUv9VeFXS/eJJZ5r4u32az94w==} @@ -966,7 +966,7 @@ packages: '@aws-sdk/util-hex-encoding': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-stream-node@3.310.0: resolution: {integrity: sha512-hueAXFK0GVvnfYFgqbF7587xZfMZff5jlIFZOHqx7XVU7bl7qrRUCnphHk8H6yZ7RoQbDPcfmHJgtEoAJg1T1Q==} @@ -976,14 +976,14 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-buffer-from': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-uri-escape@3.310.0: resolution: {integrity: sha512-drzt+aB2qo2LgtDoiy/3sVG8w63cgLkqFIa2NFlGpUgHFWTXkqtbgf4L5QdjRGKWhmZsnqkbtL7vkSWEcYDJ4Q==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-user-agent-browser@3.310.0: resolution: {integrity: sha512-yU/4QnHHuQ5z3vsUqMQVfYLbZGYwpYblPiuZx4Zo9+x0PBkNjYMqctdDcrpoH9Z2xZiDN16AmQGK1tix117ZKw==} @@ -991,7 +991,7 @@ packages: '@aws-sdk/types': 3.310.0 bowser: 2.11.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-user-agent-node@3.310.0: resolution: {integrity: sha512-Ra3pEl+Gn2BpeE7KiDGpi4zj7WJXZA5GXnGo3mjbi9+Y3zrbuhJAbdZO3mO/o7xDgMC6ph4xCTbaSGzU6b6EDg==} @@ -1005,13 +1005,13 @@ packages: '@aws-sdk/node-config-provider': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-utf8-browser@3.259.0: resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} dependencies: tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-utf8@3.310.0: resolution: {integrity: sha512-DnLfFT8uCO22uOJc0pt0DsSNau1GTisngBCDw8jQuWT5CqogMJu4b/uXmwEqfj8B3GX6Xsz8zOd6JpRlPftQoA==} @@ -1019,7 +1019,7 @@ packages: dependencies: '@aws-sdk/util-buffer-from': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/util-waiter@3.310.0: resolution: {integrity: sha512-AV5j3guH/Y4REu+Qh3eXQU9igljHuU4XjX2sADAgf54C0kkhcCCkkiuzk3IsX089nyJCqIcj5idbjdvpnH88Vw==} @@ -1028,14 +1028,14 @@ packages: '@aws-sdk/abort-controller': 3.310.0 '@aws-sdk/types': 3.310.0 tslib: 2.5.0 - dev: true + dev: false /@aws-sdk/xml-builder@3.310.0: resolution: {integrity: sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.5.0 - dev: true + dev: false /@babel/code-frame@7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} @@ -2162,18 +2162,16 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true /bowser@2.11.0: resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} - dev: true + dev: false /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - dev: true /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} @@ -2298,7 +2296,7 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - dev: true + dev: false /cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} @@ -2347,7 +2345,6 @@ packages: /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true /convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} @@ -2683,7 +2680,7 @@ packages: hasBin: true dependencies: strnum: 1.0.5 - dev: true + dev: false /fastq@1.14.0: resolution: {integrity: sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==} @@ -3651,7 +3648,7 @@ packages: resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} dependencies: brace-expansion: 1.1.11 - dev: true + dev: false /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -3989,11 +3986,11 @@ packages: /rxjs@7.5.7: resolution: {integrity: sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==} dependencies: - tslib: 2.4.1 + tslib: 2.5.0 dev: true - /s3-groundskeeper@0.2.2: - resolution: {integrity: sha512-62ntqZMhd7v85yWM+YXKsVLJdf6us6Lc+L52Ia91kRpZMgb/E9hjeXKsIoydgN9XoALoUEL+/Rp37LUrKOOl4Q==} + /s3-groundskeeper@0.3.1: + resolution: {integrity: sha512-NOATkeUjia83Dks5rTafwRauqRP3/UYXe/7psX6EXs320fKmJHKfzRNcBsVdeRJwQvE3Vc+0xJX0KkyZ5qpJpg==} hasBin: true dependencies: '@aws-sdk/client-s3': 3.315.0 @@ -4002,7 +3999,7 @@ packages: transitivePeerDependencies: - '@aws-sdk/signature-v4-crt' - aws-crt - dev: true + dev: false /semver@6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} @@ -4156,7 +4153,7 @@ packages: /strnum@1.0.5: resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} - dev: true + dev: false /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} @@ -4299,15 +4296,9 @@ packages: /tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - dev: true - - /tslib@2.4.1: - resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} - dev: true /tslib@2.5.0: resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} - dev: true /tsutils@3.21.0(typescript@5.0.4): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} @@ -4367,7 +4358,7 @@ packages: /uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true - dev: true + dev: false /v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -4456,7 +4447,7 @@ packages: /yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} - dev: true + dev: false /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} @@ -4473,7 +4464,7 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 20.2.9 - dev: true + dev: false /yargs@17.6.2: resolution: {integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==} diff --git a/src/artifact-provider-config.mts b/src/artifact-provider-config.mts index aff021e..5ba7f6b 100644 --- a/src/artifact-provider-config.mts +++ b/src/artifact-provider-config.mts @@ -2,7 +2,6 @@ export type ProviderType = 'jfrog'; export interface ArtifactProviderConfig { type: ProviderType, - protocol: string, host: string, project: string, apiKey: string, diff --git a/src/artifact-provider.mts b/src/artifact-provider.mts index 0babc5b..8f17db7 100644 --- a/src/artifact-provider.mts +++ b/src/artifact-provider.mts @@ -1,3 +1,6 @@ +import type { ByteRange } from 's3-groundskeeper'; +import type { IncomingMessage } from 'http'; + export interface Artifact { name: string, type: string, @@ -9,6 +12,7 @@ export interface Artifact { export interface ArtifactProvider { artifactsByBuildNumber(buildNumber: string): Promise; - artifactUrl(artifact: Artifact): Promise; + artifactUrl(artifact: Artifact): Promise; + getArtifactContent(artifact: Artifact, range?: ByteRange): Promise; createMetapointerFile(artifact: Artifact, fileName: string): void; } diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index 0139185..4f1f4e7 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -12,7 +12,6 @@ import { createDir, execToolToFile, removeDir } from '../fs.mjs'; import type { Config } from '../config.mjs'; import type { Deployer } from '../deployer.mjs'; import type { Packages } from '../repo.mjs'; -import { requestRange } from '../http.mjs'; const ReleaseFileTemplate = `Origin: $ORIGIN @@ -23,7 +22,6 @@ Codename: $CHANNEL\n`; interface DebDescriptor { version: string, - url: string, artifact: Artifact } @@ -109,7 +107,7 @@ export class DebBuilder implements Deployer { } private async debsByPackages(packs: Packages): Promise { - const debsPromises: Promise[] = []; + const debs: DebDescriptor[] = []; const artsByBuildNumbersPromises: Promise<{version: string, artifacts: Artifact[]}>[] = []; packs.packages.forEach(pack => { @@ -123,15 +121,14 @@ export class DebBuilder implements Deployer { artsByBuildNumbers.forEach(value => { value.artifacts.filter(artifact => artifact.type === 'deb').forEach(artifact => { - debsPromises.push((async(): Promise => ({ + debs.push({ version: value.version, artifact, - url: await this.artifactProvider.artifactUrl(artifact), - }))()); + }); }); }); - return Promise.all(debsPromises); + return debs; } private async dpkgScanpackages(): Promise { @@ -147,14 +144,14 @@ export class DebBuilder implements Deployer { } private async handleDeb(channel: string, deb: DebDescriptor): Promise { - const debUrl = deb.url; - const controlTarSizeRange = '120-129'; + const controlTarSizeRange = { start: 120, end: 129 }; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call - const cocntrolTarSize = Number((await requestRange(debUrl, controlTarSizeRange)).read().toString() + const controlTarSize = Number((await this.artifactProvider.getArtifactContent(deb.artifact, controlTarSizeRange)).read().toString() .trim()); - const controlTarRange = `132-${131 + cocntrolTarSize}`; - const controlTar = await requestRange(debUrl, controlTarRange); + const controlTarRange = { start: 132, end: 131 + controlTarSize }; + + const controlTar = await this.artifactProvider.getArtifactContent(deb.artifact, controlTarRange); const whereExtract = path.join(os.tmpdir(), `control-${crypto.randomBytes(4).toString('hex')}`); diff --git a/src/jfrog/artifact-provider.mts b/src/jfrog/artifact-provider.mts index ce55cd9..5ad1585 100644 --- a/src/jfrog/artifact-provider.mts +++ b/src/jfrog/artifact-provider.mts @@ -1,10 +1,11 @@ -import { type ArtifactoryClient, type ArtifactoryItemMeta, createArtifactoryClient } from 's3-groundskeeper'; +import { type ArtifactoryClient, type ArtifactoryItemMeta, type ByteRange, createArtifactoryClient } from 's3-groundskeeper'; import { createFile } from '../fs.mjs'; import { get } from '../http.mjs'; import type { Artifact, ArtifactProvider } from '../artifact-provider.mjs'; import type { ArtifactProviderConfig } from '../artifact-provider-config.mjs'; +import type { IncomingMessage } from 'http'; import metapointerContent from '../s3-metapointer.mjs'; interface BuildsList { @@ -31,8 +32,7 @@ export default class JfrogArtifactProvider implements ArtifactProvider { constructor(config: ArtifactProviderConfig) { this.config = config; this.artifactoryClient = createArtifactoryClient({ - protocol: this.config.protocol, - host: this.config.host, + baseUrl: new URL(this.config.host), apiKey: this.config.apiKey, user: this.config.user, }); @@ -51,7 +51,26 @@ export default class JfrogArtifactProvider implements ArtifactProvider { return result; } - public async artifactUrl(artifact: Artifact): Promise { + public async artifactUrl(artifact: Artifact): Promise { + return this.artifactoryClient.getItemUrl(await this.getArtifactoryItemMeta(artifact)); + } + + public getArtifactContent(artifact: Artifact, range?: ByteRange): Promise { + return new Promise((resolve, reject) => { + this.getArtifactoryItemMeta(artifact).then(meta => { + this.artifactoryClient.getContentStream(meta, range) + .then(value => resolve(value)) + .catch(err => reject(err)); + }); + }); + } + + // eslint-disable-next-line class-methods-use-this + public createMetapointerFile(artifact: Artifact, fileName: string): void { + createFile(fileName, metapointerContent(artifact.md5)); + } + + private async getArtifactoryItemMeta(artifact: Artifact): Promise { const aqlItemField = 'actual_md5'; const artQueryResult = await this.artifactoryClient.query(`items.find({"${aqlItemField}": "${artifact.md5}"}).include("*")`); @@ -67,12 +86,7 @@ export default class JfrogArtifactProvider implements ArtifactProvider { throw new Error(`No artifactory item found for ("${aqlItemField}": "${artifact.md5}"}`); } - return this.artifactoryClient.resolveUri(item); - } - - // eslint-disable-next-line class-methods-use-this - public createMetapointerFile(artifact: Artifact, fileName: string): void { - createFile(fileName, metapointerContent(artifact.md5)); + return item; } private async buildInfosByNumber(buildNumber: string): Promise { @@ -82,10 +96,10 @@ export default class JfrogArtifactProvider implements ArtifactProvider { const result: BuildInfo[] = []; - const buildsEndpoint = this.artifactoryClient.resolveUri(`api/build/${this.config.project}`); + const buildsEndpoint = this.artifactoryClient.resolveUrl(`api/build/${this.config.project}`); if (!this.buildsList) { - const allBuilds = await get(buildsEndpoint); + const allBuilds = await get(buildsEndpoint.toString()); this.buildsList = JSON.parse(allBuilds.toString()) as BuildsList; } @@ -103,6 +117,8 @@ export default class JfrogArtifactProvider implements ArtifactProvider { const infoPromises: Promise[] = []; + buildsEndpoint.pathname += '/'; + for (const value of buildTimes(buildNumber)) { const buildInfoEndpointUrl = new URL(buildNumber, buildsEndpoint); buildInfoEndpointUrl.searchParams.set('started', value.toISOString()); From 048b09267add42e05f888351b86b08e1d9389213 Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Fri, 16 Feb 2024 17:05:20 +0300 Subject: [PATCH 16/31] use fs.promises --- src/deb/deb-builder.mts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index 4f1f4e7..02e07e8 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -203,13 +203,7 @@ export class DebBuilder implements Deployer { const dataToAppend = `Filename: ${relativeDebPath}\nSize: ${debSize}\nSHA1: ${sha1}\nSHA256: ${sha256}\nMD5Sum: ${md5}\n`; - fs.appendFile(targetMetaPath, dataToAppend, err => { - if (err) { - throw err; - } - - resolve(); - }); + fs.promises.appendFile(targetMetaPath, dataToAppend).then(() => resolve()); }); }); } From 2e67c3b6c696d9c762f546ca86c8869bb1b65aff Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Fri, 16 Feb 2024 18:35:07 +0300 Subject: [PATCH 17/31] use temp dir in cwd --- src/deb/deb-builder.mts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index 02e07e8..cc63a5b 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -1,9 +1,7 @@ import { createGzip } from 'zlib'; -import * as crypto from 'crypto'; import * as fs from 'fs'; import * as ini from 'ini'; -import * as os from 'os'; import * as path from 'path'; import * as tar from 'tar'; @@ -35,6 +33,7 @@ export class DebBuilder implements Deployer { private readonly artifactProvider: ArtifactProvider; private readonly root: string; + private readonly temp: string; private readonly pool: string; private readonly dists: string; private readonly keys: string; @@ -47,6 +46,7 @@ export class DebBuilder implements Deployer { this.config = config; this.root = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb'); + this.temp = path.join(this.config.base.out, 'temp'); this.pool = path.join(this.root, 'pool'); this.dists = path.join(this.root, 'dists'); this.keys = path.join(this.root, 'keys'); @@ -54,9 +54,13 @@ export class DebBuilder implements Deployer { } public async plan(): Promise { - await this.prepareMetaRepository(); - await this.dpkgScanpackages(); - await this.makeRelease(); + try { + await this.prepareMetaRepository(); + await this.dpkgScanpackages(); + await this.makeRelease(); + } finally { + removeDir(this.temp); + } } public apply(): void { @@ -153,7 +157,7 @@ export class DebBuilder implements Deployer { const controlTar = await this.artifactProvider.getArtifactContent(deb.artifact, controlTarRange); - const whereExtract = path.join(os.tmpdir(), `control-${crypto.randomBytes(4).toString('hex')}`); + const whereExtract = path.join(this.temp, `control-${deb.artifact.md5}`); createDir(whereExtract); From 4a80c1d054b5829d81bdde940fad96e8a8d756bc Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Fri, 16 Feb 2024 19:21:43 +0300 Subject: [PATCH 18/31] rename channel to distribution --- src/deb/deb-builder.mts | 58 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index cc63a5b..a104ef9 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -16,15 +16,15 @@ const ReleaseFileTemplate = Label: Ubuntu/Debian Architecture: $ARCH Component: $COMPONENT -Codename: $CHANNEL\n`; +Codename: $DISTRIBUTION\n`; interface DebDescriptor { version: string, artifact: Artifact } -interface ChannelItem { - channel: string; +interface DistributionItem { + distribution: string; debs: DebDescriptor[] } @@ -38,9 +38,9 @@ export class DebBuilder implements Deployer { private readonly dists: string; private readonly keys: string; - private debRepo: ChannelItem[] = []; + private debRepo: DistributionItem[] = []; - private archesByChannel: Map> = new Map(); + private archesByDistribution: Map> = new Map(); constructor(artifactProvider: ArtifactProvider, config: Config) { this.config = config; @@ -71,35 +71,35 @@ export class DebBuilder implements Deployer { return `${this.config.debBuilder.applicationName}-${version}_${arch}.deb`; } - private async makeReleaseFileAndSign(channel: string, arch: string): Promise { + private async makeReleaseFileAndSign(distribution: string, arch: string): Promise { const publicKeyPath = path.join(this.keys, 'desktop.asc'); createDir(this.keys); await fs.promises.copyFile(this.config.debBuilder.gpgPublicKeyPath, publicKeyPath); const releaseContent = ReleaseFileTemplate .replace('$ORIGIN', this.config.debBuilder.origin) - .replace('$CHANNEL', channel) + .replace('$DISTRIBUTION', distribution) .replace('$ARCH', arch) .replace('$COMPONENT', this.config.debBuilder.component); - const releaseFilePath = path.join(this.dists, channel, 'Release'); - const releaseGpgFilePath = path.join(this.dists, channel, 'Release.gpg'); - const inReleaseFilePath = path.join(this.dists, channel, 'InRelease'); + const releaseFilePath = path.join(this.dists, distribution, 'Release'); + const releaseGpgFilePath = path.join(this.dists, distribution, 'Release.gpg'); + const inReleaseFilePath = path.join(this.dists, distribution, 'InRelease'); await fs.promises.writeFile(releaseFilePath, releaseContent); - await execToolToFile('apt-ftparchive', ['release', `${this.dists}/${channel}`], releaseFilePath, true); + await execToolToFile('apt-ftparchive', ['release', `${this.dists}/${distribution}`], releaseFilePath, true); await execToolToFile('gpg', ['--no-tty', '--default-key', this.config.debBuilder.gpgKeyName, '-abs', '-o', releaseGpgFilePath, releaseFilePath]); await execToolToFile('gpg', ['--no-tty', '--default-key', this.config.debBuilder.gpgKeyName, '--clearsign', '-o', inReleaseFilePath, releaseFilePath]); } private async prepareMetaRepository(): Promise { - const debsPromises: Promise<{channel: string, debs: DebDescriptor[]}>[] = []; + const debsPromises: Promise<{distribution: string, debs: DebDescriptor[]}>[] = []; - this.config.base.repo.forEach(channelEntry => { - debsPromises.push((async(): Promise<{ channel: string, debs: DebDescriptor[] }> => ({ - channel: channelEntry.channel, - debs: await this.debsByPackages(channelEntry.packages), + this.config.base.repo.forEach(distributionEntry => { + debsPromises.push((async(): Promise<{ distribution: string, debs: DebDescriptor[] }> => ({ + distribution: distributionEntry.channel, + debs: await this.debsByPackages(distributionEntry.packages), }))()); }); @@ -138,16 +138,16 @@ export class DebBuilder implements Deployer { private async dpkgScanpackages(): Promise { const promises: Promise[] = []; - this.debRepo.forEach(channel => { - channel.debs.forEach(deb => { - promises.push(this.handleDeb(channel.channel, deb)); + this.debRepo.forEach(distribution => { + distribution.debs.forEach(deb => { + promises.push(this.handleDeb(distribution.distribution, deb)); }); }); await Promise.all(promises); } - private async handleDeb(channel: string, deb: DebDescriptor): Promise { + private async handleDeb(distribution: string, deb: DebDescriptor): Promise { const controlTarSizeRange = { start: 120, end: 129 }; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call @@ -170,16 +170,16 @@ export class DebBuilder implements Deployer { const controlMeta = ini.parse(controlMetaContent); const arch = controlMeta['Architecture']; - const archesSet = this.archesByChannel.get(channel); + const archesSet = this.archesByDistribution.get(distribution); if (archesSet) { archesSet.add(arch); } else { - this.archesByChannel.set(channel, new Set([arch])); + this.archesByDistribution.set(distribution, new Set([arch])); } const targetMetaPath = path.join(this.dists, - channel, + distribution, this.config.debBuilder.component, `binary-${arch}`, `${this.debName(deb.version, arch)}.meta`); @@ -192,7 +192,7 @@ export class DebBuilder implements Deployer { this.config.debBuilder.component, `${this.config.debBuilder.applicationName[0]}`, this.config.debBuilder.applicationName, - channel, + distribution, this.debName(deb.version, arch)); const relativeDebPath = path.relative(this.root, debPath); this.artifactProvider.createMetapointerFile(deb.artifact, debPath); @@ -227,8 +227,8 @@ export class DebBuilder implements Deployer { const compressPromises: Promise[] = []; - this.debRepo.forEach(channelEntry => { - const distsRoot = path.join(this.dists, channelEntry.channel, this.config.debBuilder.component); + this.debRepo.forEach(distributionEntry => { + const distsRoot = path.join(this.dists, distributionEntry.distribution, this.config.debBuilder.component); const distsByArch = fs.readdirSync(distsRoot).map(dist => path.join(distsRoot, dist)); distsByArch.forEach(dist => { @@ -256,12 +256,12 @@ export class DebBuilder implements Deployer { const releasesPromises: Promise[] = []; this.debRepo.forEach(chan => { - const archesSet = this.archesByChannel.get(chan.channel); + const archesSet = this.archesByDistribution.get(chan.distribution); if (!archesSet) { - throw new Error('No arch was found for channel'); + throw new Error('No arch was found for distribution'); } - releasesPromises.push(this.makeReleaseFileAndSign(chan.channel, [...archesSet.values()].join(' '))); + releasesPromises.push(this.makeReleaseFileAndSign(chan.distribution, [...archesSet.values()].join(' '))); }); return Promise.all(releasesPromises); From 0f0c7b41aa5d88386969251df1451eaa8a01db13 Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Fri, 15 Mar 2024 16:26:47 +0300 Subject: [PATCH 19/31] review notes fix --- src/artifact-provider.mts | 1 - src/deb/deb-builder.mts | 3 ++- src/fs.mts | 4 ---- src/http.mts | 18 +++++++++--------- src/jfrog/artifact-provider.mts | 11 ++--------- src/s3-metapointer.mts | 9 ++++++++- 6 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/artifact-provider.mts b/src/artifact-provider.mts index 8f17db7..efe3c90 100644 --- a/src/artifact-provider.mts +++ b/src/artifact-provider.mts @@ -14,5 +14,4 @@ export interface ArtifactProvider { artifactsByBuildNumber(buildNumber: string): Promise; artifactUrl(artifact: Artifact): Promise; getArtifactContent(artifact: Artifact, range?: ByteRange): Promise; - createMetapointerFile(artifact: Artifact, fileName: string): void; } diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index a104ef9..8b0c207 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -8,6 +8,7 @@ import * as tar from 'tar'; import type { Artifact, ArtifactProvider } from '../artifact-provider.mjs'; import { createDir, execToolToFile, removeDir } from '../fs.mjs'; import type { Config } from '../config.mjs'; +import { createMetapointerFile } from '../s3-metapointer.mjs'; import type { Deployer } from '../deployer.mjs'; import type { Packages } from '../repo.mjs'; @@ -195,7 +196,7 @@ export class DebBuilder implements Deployer { distribution, this.debName(deb.version, arch)); const relativeDebPath = path.relative(this.root, debPath); - this.artifactProvider.createMetapointerFile(deb.artifact, debPath); + createMetapointerFile(deb.artifact.md5, debPath); const debSize = controlTar.headers['content-range']?.split('/')[1]; const sha1 = controlTar.headers['x-checksum-sha1']; const sha256 = controlTar.headers['x-checksum-sha256']; diff --git a/src/fs.mts b/src/fs.mts index a2363b4..f3d619c 100644 --- a/src/fs.mts +++ b/src/fs.mts @@ -22,10 +22,6 @@ export function removeDir(dirName: string): void { } } -export function createMetapointerContent(fileMd5Hash: string): string { - return `#metapointer jfrogart\noid md5:${fileMd5Hash}`; -} - // eslint-disable-next-line max-params export async function execToolToFile(tool: string, args: string[], outputPath?: string, append?: boolean): Promise { if (!append && outputPath && existsSync(outputPath)) { diff --git a/src/http.mts b/src/http.mts index ba35c16..6047514 100644 --- a/src/http.mts +++ b/src/http.mts @@ -12,7 +12,7 @@ export interface RequestData { redirectHandler?: (url: string) => string | undefined; } -export function requestStream(url: string, method: string, requestData?: RequestData): Promise { +export function requestStream(url: URL, method: string, requestData?: RequestData): Promise { return new Promise((resolve, reject) => { try { const req = httpRequest(url, { method }); @@ -22,7 +22,7 @@ export function requestStream(url: string, method: string, requestData?: Request if (incomingMessage.statusCode !== 200) { const stCode = incomingMessage.statusCode ?? 'NO_CODE'; const stMessage = incomingMessage.statusMessage ?? 'NO_MESSAGE'; - const message = `[${method} ${url}]:${stCode}/${stMessage}`; + const message = `[${method} ${url.toString()}]:${stCode}/${stMessage}`; reject(new Error(message)); } @@ -31,7 +31,7 @@ export function requestStream(url: string, method: string, requestData?: Request .on('error', (err: Error) => { const errno = (err as {errno?: string}).errno ?? ''; if (errno === 'ETIMEDOUT') { - reject(new Error(`Request (${url}) timeout.`)); + reject(new Error(`Request (${url.toString()}) timeout.`)); } else { reject(err); } @@ -61,7 +61,7 @@ export function requestStream(url: string, method: string, requestData?: Request }); } -export async function request(url: string, method: string, requestData?: RequestData): Promise { +export async function request(url: URL, method: string, requestData?: RequestData): Promise { const responseStream = await requestStream(url, method, requestData); let buffer: Buffer | undefined = undefined; @@ -74,7 +74,7 @@ export async function request(url: string, method: string, requestData?: Request return buffer ? buffer : Buffer.from(''); } -export function requestRange(url: string, range: string): Promise { +export function requestRange(url: URL, range: string): Promise { return new Promise((resolve, reject) => { try { const req = httpRequest(url, { method: 'GET' }); @@ -88,7 +88,7 @@ export function requestRange(url: string, range: string): Promise { const errno = (err as {errno?: string}).errno ?? ''; if (errno === 'ETIMEDOUT') { - reject(new Error(`Request (${url}) timeout.`)); + reject(new Error(`Request (${url.toString()}) timeout.`)); } else { reject(err); } @@ -114,10 +114,10 @@ export function requestRange(url: string, range: string): Promise { +export function get(url: URL): Promise { return request(url, 'GET', undefined); } -export function post(url: string, requestData?: RequestData): Promise { +export function post(url: URL, requestData?: RequestData): Promise { return request(url, 'POST', requestData); } diff --git a/src/jfrog/artifact-provider.mts b/src/jfrog/artifact-provider.mts index 5ad1585..91b4ff9 100644 --- a/src/jfrog/artifact-provider.mts +++ b/src/jfrog/artifact-provider.mts @@ -1,12 +1,10 @@ import { type ArtifactoryClient, type ArtifactoryItemMeta, type ByteRange, createArtifactoryClient } from 's3-groundskeeper'; -import { createFile } from '../fs.mjs'; import { get } from '../http.mjs'; import type { Artifact, ArtifactProvider } from '../artifact-provider.mjs'; import type { ArtifactProviderConfig } from '../artifact-provider-config.mjs'; import type { IncomingMessage } from 'http'; -import metapointerContent from '../s3-metapointer.mjs'; interface BuildsList { buildsNumbers: { @@ -65,11 +63,6 @@ export default class JfrogArtifactProvider implements ArtifactProvider { }); } - // eslint-disable-next-line class-methods-use-this - public createMetapointerFile(artifact: Artifact, fileName: string): void { - createFile(fileName, metapointerContent(artifact.md5)); - } - private async getArtifactoryItemMeta(artifact: Artifact): Promise { const aqlItemField = 'actual_md5'; @@ -99,7 +92,7 @@ export default class JfrogArtifactProvider implements ArtifactProvider { const buildsEndpoint = this.artifactoryClient.resolveUrl(`api/build/${this.config.project}`); if (!this.buildsList) { - const allBuilds = await get(buildsEndpoint.toString()); + const allBuilds = await get(buildsEndpoint); this.buildsList = JSON.parse(allBuilds.toString()) as BuildsList; } @@ -122,7 +115,7 @@ export default class JfrogArtifactProvider implements ArtifactProvider { for (const value of buildTimes(buildNumber)) { const buildInfoEndpointUrl = new URL(buildNumber, buildsEndpoint); buildInfoEndpointUrl.searchParams.set('started', value.toISOString()); - infoPromises.push(get(buildInfoEndpointUrl.toString())); + infoPromises.push(get(buildInfoEndpointUrl)); } const infos = await Promise.all(infoPromises); diff --git a/src/s3-metapointer.mts b/src/s3-metapointer.mts index ce93b26..5241d47 100644 --- a/src/s3-metapointer.mts +++ b/src/s3-metapointer.mts @@ -1,3 +1,10 @@ -export default function metapointerContent(fileMd5Hash: string): string { +import { createFile } from './fs.mjs'; + +export function content(fileMd5Hash: string): string { return `#metapointer jfrogart\noid md5:${fileMd5Hash}`; } + +// eslint-disable-next-line class-methods-use-this +export function createMetapointerFile(md5: string, fileName: string): void { + createFile(fileName, content(md5)); +} From 69d541f3d3a6af25c026c71ded5d839bb8bd2871 Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Mon, 18 Mar 2024 16:56:35 +0300 Subject: [PATCH 20/31] move artifactory related logic from deb builder to config --- src/config.mts | 13 +-- src/deb/deb-builder-config.mts | 23 +++++- src/deb/deb-builder.mts | 145 +++++++++++++-------------------- src/index.mts | 19 +---- src/index.spec.mts | 4 +- tests/index.spec.mts | 4 +- 6 files changed, 87 insertions(+), 121 deletions(-) diff --git a/src/config.mts b/src/config.mts index 8e86587..788996f 100644 --- a/src/config.mts +++ b/src/config.mts @@ -1,19 +1,10 @@ import path from 'path'; import { pathToFileURL } from 'url'; -import type { ArtifactProviderConfig } from './artifact-provider-config.mjs'; -import type { DebBuilderConfig } from './deb/deb-builder-config.mjs'; -import type { Repo } from './repo.mjs'; - -interface BaseConfig { - out: string; - repo: Repo; -} +import type { Deployer } from './deployer.mjs'; export interface Config { - base: BaseConfig; - artifactsProvider: ArtifactProviderConfig; - debBuilder: DebBuilderConfig; + deployers: Deployer[]; } export class ConfigProvider { diff --git a/src/deb/deb-builder-config.mts b/src/deb/deb-builder-config.mts index 07e02b3..9977e7e 100644 --- a/src/deb/deb-builder-config.mts +++ b/src/deb/deb-builder-config.mts @@ -1,7 +1,28 @@ +import type { Artifact } from '../artifact-provider.mjs'; + export interface DebBuilderConfig { + out: string, gpgPublicKeyPath: string; gpgKeyName: string; applicationName: string; - component: string; origin: string; + repo: DebRepo; +} + +type Distribution = string; +type UbuntuComponentsEnum = 'main' | 'universe' | 'restricted' | 'multiverse'; + +export type UbuntuComponent = { + [key in UbuntuComponentsEnum]: string; +}; + +export interface DebDescriptor { + version: string, + artifact: Artifact +} + +export interface DebRepo { + [key: Distribution]: { + [key in keyof UbuntuComponent]?: DebDescriptor[] + } } diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index 8b0c207..45d6332 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -5,12 +5,10 @@ import * as ini from 'ini'; import * as path from 'path'; import * as tar from 'tar'; -import type { Artifact, ArtifactProvider } from '../artifact-provider.mjs'; import { createDir, execToolToFile, removeDir } from '../fs.mjs'; -import type { Config } from '../config.mjs'; -import { createMetapointerFile } from '../s3-metapointer.mjs'; +import type { DebBuilderConfig, DebDescriptor, DebRepo } from './deb-builder-config.mjs'; +import type { ArtifactProvider } from '../artifact-provider.mjs'; import type { Deployer } from '../deployer.mjs'; -import type { Packages } from '../repo.mjs'; const ReleaseFileTemplate = `Origin: $ORIGIN @@ -19,19 +17,32 @@ Architecture: $ARCH Component: $COMPONENT Codename: $DISTRIBUTION\n`; -interface DebDescriptor { - version: string, - artifact: Artifact +function iterateComponents(repo: DebRepo, callback: (distribution: string, component: string, deb: DebDescriptor[]) => void): void { + const distributions = Object.keys(repo); + + distributions.forEach(distribution => { + const componentsFordistribution = repo[distribution]; + if (componentsFordistribution) { + Object.entries(componentsFordistribution).forEach(entry => { + const [component, debs] = entry; + callback(distribution, component, debs); + }); + } + }); } -interface DistributionItem { - distribution: string; - debs: DebDescriptor[] +function iterateDebs(repo: DebRepo, callback: (distribution: string, component: string, deb: DebDescriptor) => void): void { + iterateComponents(repo, (distribution: string, component: string, debs: DebDescriptor[]) => { + debs.forEach(deb => { + callback(distribution, component, deb); + }); + }); } export class DebBuilder implements Deployer { - private readonly config: Config; + private readonly config: DebBuilderConfig; private readonly artifactProvider: ArtifactProvider; + private readonly metapointerCreator: (md5: string, path: string) => void; private readonly root: string; private readonly temp: string; @@ -39,24 +50,22 @@ export class DebBuilder implements Deployer { private readonly dists: string; private readonly keys: string; - private debRepo: DistributionItem[] = []; + private archesByDistComp: Map> = new Map(); - private archesByDistribution: Map> = new Map(); - - constructor(artifactProvider: ArtifactProvider, config: Config) { + constructor(config: DebBuilderConfig, artifactProvider: ArtifactProvider, metapointerCreator: (md5: string, path: string) => void) { this.config = config; + this.artifactProvider = artifactProvider; + this.metapointerCreator = metapointerCreator; - this.root = path.join(this.config.base.out, 'repo', this.config.debBuilder.applicationName, 'deb'); - this.temp = path.join(this.config.base.out, 'temp'); + this.root = path.join(this.config.out); + this.temp = path.join(this.config.out, 'temp'); this.pool = path.join(this.root, 'pool'); this.dists = path.join(this.root, 'dists'); this.keys = path.join(this.root, 'keys'); - this.artifactProvider = artifactProvider; } public async plan(): Promise { try { - await this.prepareMetaRepository(); await this.dpkgScanpackages(); await this.makeRelease(); } finally { @@ -69,86 +78,42 @@ export class DebBuilder implements Deployer { } private debName(version: string, arch: string): string { - return `${this.config.debBuilder.applicationName}-${version}_${arch}.deb`; + return `${this.config.applicationName}-${version}_${arch}.deb`; } - private async makeReleaseFileAndSign(distribution: string, arch: string): Promise { + private async makeReleaseFileAndSign(distribution: string, component: string, arch: string): Promise { const publicKeyPath = path.join(this.keys, 'desktop.asc'); createDir(this.keys); - await fs.promises.copyFile(this.config.debBuilder.gpgPublicKeyPath, publicKeyPath); + await fs.promises.copyFile(this.config.gpgPublicKeyPath, publicKeyPath); const releaseContent = ReleaseFileTemplate - .replace('$ORIGIN', this.config.debBuilder.origin) + .replace('$ORIGIN', this.config.origin) .replace('$DISTRIBUTION', distribution) .replace('$ARCH', arch) - .replace('$COMPONENT', this.config.debBuilder.component); + .replace('$COMPONENT', component); - const releaseFilePath = path.join(this.dists, distribution, 'Release'); - const releaseGpgFilePath = path.join(this.dists, distribution, 'Release.gpg'); - const inReleaseFilePath = path.join(this.dists, distribution, 'InRelease'); + const releaseFilePath = path.join(this.dists, distribution, component, 'Release'); + const releaseGpgFilePath = path.join(this.dists, distribution, component, 'Release.gpg'); + const inReleaseFilePath = path.join(this.dists, distribution, component, 'InRelease'); await fs.promises.writeFile(releaseFilePath, releaseContent); await execToolToFile('apt-ftparchive', ['release', `${this.dists}/${distribution}`], releaseFilePath, true); - await execToolToFile('gpg', ['--no-tty', '--default-key', this.config.debBuilder.gpgKeyName, '-abs', '-o', releaseGpgFilePath, releaseFilePath]); - await execToolToFile('gpg', ['--no-tty', '--default-key', this.config.debBuilder.gpgKeyName, '--clearsign', '-o', inReleaseFilePath, releaseFilePath]); - } - - private async prepareMetaRepository(): Promise { - const debsPromises: Promise<{distribution: string, debs: DebDescriptor[]}>[] = []; - - this.config.base.repo.forEach(distributionEntry => { - debsPromises.push((async(): Promise<{ distribution: string, debs: DebDescriptor[] }> => ({ - distribution: distributionEntry.channel, - debs: await this.debsByPackages(distributionEntry.packages), - }))()); - }); - - const debs = await Promise.all(debsPromises); - - debs.forEach(entry => { - this.debRepo.push(entry); - }); - } - - private async debsByPackages(packs: Packages): Promise { - const debs: DebDescriptor[] = []; - const artsByBuildNumbersPromises: Promise<{version: string, artifacts: Artifact[]}>[] = []; - - packs.packages.forEach(pack => { - artsByBuildNumbersPromises.push((async(): Promise<{ version: string, artifacts: Artifact[] }> => ({ - version: pack.version, - artifacts: await this.artifactProvider.artifactsByBuildNumber(pack.buildNumber), - }))()); - }); - - const artsByBuildNumbers = await Promise.all(artsByBuildNumbersPromises); - - artsByBuildNumbers.forEach(value => { - value.artifacts.filter(artifact => artifact.type === 'deb').forEach(artifact => { - debs.push({ - version: value.version, - artifact, - }); - }); - }); - - return debs; + await execToolToFile('gpg', ['--no-tty', '--default-key', this.config.gpgKeyName, '-abs', '-o', releaseGpgFilePath, releaseFilePath]); + await execToolToFile('gpg', ['--no-tty', '--default-key', this.config.gpgKeyName, '--clearsign', '-o', inReleaseFilePath, releaseFilePath]); } private async dpkgScanpackages(): Promise { const promises: Promise[] = []; - this.debRepo.forEach(distribution => { - distribution.debs.forEach(deb => { - promises.push(this.handleDeb(distribution.distribution, deb)); - }); + iterateDebs(this.config.repo, (distribution, component, deb) => { + promises.push(this.handleDeb(distribution, component, deb)); }); await Promise.all(promises); } - private async handleDeb(distribution: string, deb: DebDescriptor): Promise { + private async handleDeb(distribution: string, component: string, deb: DebDescriptor): Promise { const controlTarSizeRange = { start: 120, end: 129 }; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call @@ -171,17 +136,17 @@ export class DebBuilder implements Deployer { const controlMeta = ini.parse(controlMetaContent); const arch = controlMeta['Architecture']; - const archesSet = this.archesByDistribution.get(distribution); + const archesSet = this.archesByDistComp.get(`${distribution}/${component}`); if (archesSet) { archesSet.add(arch); } else { - this.archesByDistribution.set(distribution, new Set([arch])); + this.archesByDistComp.set(`${distribution}/${component}`, new Set([arch])); } const targetMetaPath = path.join(this.dists, distribution, - this.config.debBuilder.component, + component, `binary-${arch}`, `${this.debName(deb.version, arch)}.meta`); createDir(path.dirname(targetMetaPath)); @@ -190,13 +155,13 @@ export class DebBuilder implements Deployer { removeDir(whereExtract); const debPath = path.join(this.pool, - this.config.debBuilder.component, - `${this.config.debBuilder.applicationName[0]}`, - this.config.debBuilder.applicationName, + component, + `${this.config.applicationName[0]}`, + this.config.applicationName, distribution, this.debName(deb.version, arch)); const relativeDebPath = path.relative(this.root, debPath); - createMetapointerFile(deb.artifact.md5, debPath); + this.metapointerCreator(deb.artifact.md5, debPath); const debSize = controlTar.headers['content-range']?.split('/')[1]; const sha1 = controlTar.headers['x-checksum-sha1']; const sha256 = controlTar.headers['x-checksum-sha256']; @@ -228,11 +193,11 @@ export class DebBuilder implements Deployer { const compressPromises: Promise[] = []; - this.debRepo.forEach(distributionEntry => { - const distsRoot = path.join(this.dists, distributionEntry.distribution, this.config.debBuilder.component); - const distsByArch = fs.readdirSync(distsRoot).map(dist => path.join(distsRoot, dist)); + iterateComponents(this.config.repo, (distribution, component) => { + const componentssRoot = path.join(this.dists, distribution, component); + const componentsByArch = fs.readdirSync(componentssRoot).map(dist => path.join(componentssRoot, dist)); - distsByArch.forEach(dist => { + componentsByArch.forEach(dist => { const targetPackagesFile = path.join(dist, 'Packages'); const metaFiles = fs.readdirSync(dist) .filter(fileName => fileName.endsWith('.meta')) @@ -256,13 +221,13 @@ export class DebBuilder implements Deployer { const releasesPromises: Promise[] = []; - this.debRepo.forEach(chan => { - const archesSet = this.archesByDistribution.get(chan.distribution); + iterateComponents(this.config.repo, (distribution, component) => { + const archesSet = this.archesByDistComp.get(`${distribution}/${component}`); if (!archesSet) { throw new Error('No arch was found for distribution'); } - releasesPromises.push(this.makeReleaseFileAndSign(chan.distribution, [...archesSet.values()].join(' '))); + releasesPromises.push(this.makeReleaseFileAndSign(distribution, component, [...archesSet.values()].join(' '))); }); return Promise.all(releasesPromises); diff --git a/src/index.mts b/src/index.mts index 4087883..8dc8aa7 100644 --- a/src/index.mts +++ b/src/index.mts @@ -1,26 +1,15 @@ import type { Config } from './config.mjs'; -import { DebBuilder } from './deb/deb-builder.mjs'; -import type { Deployer } from './deployer.mjs'; -import JfrogArtifactProvider from './jfrog/artifact-provider.mjs'; export { type Config, createConfigProvider } from './config.mjs'; -export function plan(config: Config): Promise { - const artifactsProvider = new JfrogArtifactProvider(config.artifactsProvider); - - const builders: Deployer[] = []; - - if (config.debBuilder) { - builders.push(new DebBuilder(artifactsProvider, config)); - } - +export async function plan(config: Config): Promise { const planPromises: Promise[] = []; - for (const builder of builders) { - planPromises.push(builder.plan()); + for (const deployer of config.deployers) { + planPromises.push(deployer.plan()); } - return Promise.all(planPromises); + await Promise.all(planPromises); } export function apply(): void { diff --git a/src/index.spec.mts b/src/index.spec.mts index 0d4f8d9..c52d111 100644 --- a/src/index.spec.mts +++ b/src/index.spec.mts @@ -9,7 +9,7 @@ describe('apply', () => { }); describe('plan', () => { - it('should return undefined', () => { - expect(plan()).toBe(undefined); + it('should return undefined', async() => { + expect(await plan({ deployers: [] })).toBe(undefined); }); }); diff --git a/tests/index.spec.mts b/tests/index.spec.mts index 01c72ce..4fd906e 100644 --- a/tests/index.spec.mts +++ b/tests/index.spec.mts @@ -9,7 +9,7 @@ describe('apply', () => { }); describe('plan', () => { - it('should return undefined', () => { - expect(plan()).toBe(undefined); + it('should return undefined', async() => { + expect(await plan({ deployers: [] })).toBe(undefined); }); }); From debc292b5b06c6decff65f7432794235e7966b30 Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Wed, 20 Mar 2024 14:28:57 +0300 Subject: [PATCH 21/31] fix releases path, configure deb builder with package creator function --- src/deb/deb-builder.mts | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index 45d6332..f18bc6b 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -42,7 +42,7 @@ function iterateDebs(repo: DebRepo, callback: (distribution: string, component: export class DebBuilder implements Deployer { private readonly config: DebBuilderConfig; private readonly artifactProvider: ArtifactProvider; - private readonly metapointerCreator: (md5: string, path: string) => void; + private readonly packageCreator: (md5: string, path: string) => (Promise | void); private readonly root: string; private readonly temp: string; @@ -52,10 +52,10 @@ export class DebBuilder implements Deployer { private archesByDistComp: Map> = new Map(); - constructor(config: DebBuilderConfig, artifactProvider: ArtifactProvider, metapointerCreator: (md5: string, path: string) => void) { + constructor(config: DebBuilderConfig, artifactProvider: ArtifactProvider, packageCreator: (md5: string, path: string) => (Promise | void)) { this.config = config; this.artifactProvider = artifactProvider; - this.metapointerCreator = metapointerCreator; + this.packageCreator = packageCreator; this.root = path.join(this.config.out); this.temp = path.join(this.config.out, 'temp'); @@ -92,9 +92,9 @@ export class DebBuilder implements Deployer { .replace('$ARCH', arch) .replace('$COMPONENT', component); - const releaseFilePath = path.join(this.dists, distribution, component, 'Release'); - const releaseGpgFilePath = path.join(this.dists, distribution, component, 'Release.gpg'); - const inReleaseFilePath = path.join(this.dists, distribution, component, 'InRelease'); + const releaseFilePath = path.join(this.dists, distribution, 'Release'); + const releaseGpgFilePath = path.join(this.dists, distribution, 'Release.gpg'); + const inReleaseFilePath = path.join(this.dists, distribution, 'InRelease'); await fs.promises.writeFile(releaseFilePath, releaseContent); @@ -127,6 +127,8 @@ export class DebBuilder implements Deployer { createDir(whereExtract); + let createFilePromise: Promise | undefined = undefined; + await new Promise(resolve => { controlTar .pipe(tar.extract({ cwd: whereExtract, strip: 1 }, ['./control'])) @@ -161,7 +163,6 @@ export class DebBuilder implements Deployer { distribution, this.debName(deb.version, arch)); const relativeDebPath = path.relative(this.root, debPath); - this.metapointerCreator(deb.artifact.md5, debPath); const debSize = controlTar.headers['content-range']?.split('/')[1]; const sha1 = controlTar.headers['x-checksum-sha1']; const sha256 = controlTar.headers['x-checksum-sha256']; @@ -174,8 +175,18 @@ export class DebBuilder implements Deployer { const dataToAppend = `Filename: ${relativeDebPath}\nSize: ${debSize}\nSHA1: ${sha1}\nSHA256: ${sha256}\nMD5Sum: ${md5}\n`; fs.promises.appendFile(targetMetaPath, dataToAppend).then(() => resolve()); + + const createFileOperation = this.packageCreator(deb.artifact.md5, debPath); + + if(createFileOperation instanceof Promise) { + createFilePromise = createFileOperation + } }); }); + + if (createFilePromise) { + await createFilePromise; + } } private async makeRelease(): Promise<{}> { From e1d71d5871e13df6e4c1b879ccb5b8b517b3927d Mon Sep 17 00:00:00 2001 From: Egor Kushnarev Date: Wed, 20 Mar 2024 14:58:40 +0300 Subject: [PATCH 22/31] don't deploy pub key --- src/deb/deb-builder-config.mts | 1 - src/deb/deb-builder.mts | 7 ------- 2 files changed, 8 deletions(-) diff --git a/src/deb/deb-builder-config.mts b/src/deb/deb-builder-config.mts index 9977e7e..8969f9f 100644 --- a/src/deb/deb-builder-config.mts +++ b/src/deb/deb-builder-config.mts @@ -2,7 +2,6 @@ import type { Artifact } from '../artifact-provider.mjs'; export interface DebBuilderConfig { out: string, - gpgPublicKeyPath: string; gpgKeyName: string; applicationName: string; origin: string; diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index f18bc6b..ebb40ee 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -48,8 +48,6 @@ export class DebBuilder implements Deployer { private readonly temp: string; private readonly pool: string; private readonly dists: string; - private readonly keys: string; - private archesByDistComp: Map> = new Map(); constructor(config: DebBuilderConfig, artifactProvider: ArtifactProvider, packageCreator: (md5: string, path: string) => (Promise | void)) { @@ -61,7 +59,6 @@ export class DebBuilder implements Deployer { this.temp = path.join(this.config.out, 'temp'); this.pool = path.join(this.root, 'pool'); this.dists = path.join(this.root, 'dists'); - this.keys = path.join(this.root, 'keys'); } public async plan(): Promise { @@ -82,10 +79,6 @@ export class DebBuilder implements Deployer { } private async makeReleaseFileAndSign(distribution: string, component: string, arch: string): Promise { - const publicKeyPath = path.join(this.keys, 'desktop.asc'); - createDir(this.keys); - await fs.promises.copyFile(this.config.gpgPublicKeyPath, publicKeyPath); - const releaseContent = ReleaseFileTemplate .replace('$ORIGIN', this.config.origin) .replace('$DISTRIBUTION', distribution) From f664580706570451b9feafd94d7919e6c73613b4 Mon Sep 17 00:00:00 2001 From: Stanislav Makarov Date: Thu, 21 Mar 2024 04:49:28 +0300 Subject: [PATCH 23/31] reexport public entities from index --- src/cli.mts | 3 ++- src/index.mts | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/cli.mts b/src/cli.mts index 1952798..d263d13 100644 --- a/src/cli.mts +++ b/src/cli.mts @@ -1,7 +1,8 @@ import { exit } from 'process'; import yargs from 'yargs'; -import { apply, createConfigProvider, plan } from './index.mjs'; +import { apply, plan } from './index.mjs'; +import { createConfigProvider } from './config.mjs'; import { getMessageOfError } from './utils.mjs'; type CommandLineArgs = Awaited>; diff --git a/src/index.mts b/src/index.mts index 8dc8aa7..a14dce5 100644 --- a/src/index.mts +++ b/src/index.mts @@ -1,6 +1,11 @@ import type { Config } from './config.mjs'; - -export { type Config, createConfigProvider } from './config.mjs'; +export type { Config }; +export type { Artifact, ArtifactProvider } from './artifact-provider.mjs'; +export type { ProviderType, ArtifactProviderConfig } from './artifact-provider-config.mjs'; +export type { DebBuilderConfig, DebDescriptor, DebRepo } from './deb/deb-builder-config.mjs'; +export { DebBuilder } from './deb/deb-builder.mjs'; +export { default as JfrogArtifactProvider } from './jfrog/artifact-provider.mjs'; +export { createMetapointerFile as createS3MetapointerFile } from './s3-metapointer.mjs'; export async function plan(config: Config): Promise { const planPromises: Promise[] = []; From b058bdc4670ca14377a2991f353f9846be6c7f69 Mon Sep 17 00:00:00 2001 From: Stanislav Makarov Date: Thu, 21 Mar 2024 05:16:17 +0300 Subject: [PATCH 24/31] use .gitignore as ignore list for ESLint --- eslint.config.mjs | 8 ++----- package.json | 1 + pnpm-lock.yaml | 60 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 6 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index d2b39ad..db1f803 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,15 +1,11 @@ +import gitIgnore from 'eslint-config-flat-gitignore'; import tsParser from '@typescript-eslint/parser'; import tsPlugin from '@typescript-eslint/eslint-plugin'; export default [ 'eslint:all', // 'plugin:@typescript-eslint/recommended', - { - ignores: [ - 'coverage/**', - 'dist/**', - ], - }, + gitIgnore(), { rules: { 'array-element-newline': ['error', 'consistent'], diff --git a/package.json b/package.json index 49e94bf..6253d73 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@typescript-eslint/parser": "^5.45.1", "editorconfig-checker": "^4.0.2", "eslint": "^8.29.0", + "eslint-config-flat-gitignore": "^0.1.3", "husky": "^8.0.0", "jest": "^29.3.1", "lint-staged": "^13.0.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a56962f..5029eac 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,6 +53,9 @@ importers: eslint: specifier: ^8.29.0 version: 8.29.0 + eslint-config-flat-gitignore: + specifier: ^0.1.3 + version: 0.1.3 husky: specifier: ^8.0.0 version: 8.0.2 @@ -2478,6 +2481,13 @@ packages: engines: {node: '>=10'} dev: true + /eslint-config-flat-gitignore@0.1.3: + resolution: {integrity: sha512-oQD+dEZv3RThN60tFqGFt+NJcO1DmssUcP+T/nlX+ZzEoEvVUYH0GU9X/VlmDXsbMsS9mONI1HrlxLgtKojw7w==} + dependencies: + find-up: 7.0.0 + parse-gitignore: 2.0.0 + dev: true + /eslint-scope@5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} @@ -2724,6 +2734,15 @@ packages: path-exists: 4.0.0 dev: true + /find-up@7.0.0: + resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} + engines: {node: '>=18'} + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + unicorn-magic: 0.1.0 + dev: true + /flat-cache@3.0.4: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -3575,6 +3594,13 @@ packages: p-locate: 5.0.0 dev: true + /locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-locate: 6.0.0 + dev: true + /lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} dev: true @@ -3779,6 +3805,13 @@ packages: yocto-queue: 0.1.0 dev: true + /p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + yocto-queue: 1.0.0 + dev: true + /p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -3793,6 +3826,13 @@ packages: p-limit: 3.1.0 dev: true + /p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-limit: 4.0.0 + dev: true + /p-map@4.0.0: resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} engines: {node: '>=10'} @@ -3812,6 +3852,11 @@ packages: callsites: 3.1.0 dev: true + /parse-gitignore@2.0.0: + resolution: {integrity: sha512-RmVuCHWsfu0QPNW+mraxh/xjQVw/lhUCUru8Zni3Ctq3AoMhpDTq0OVdKS6iesd6Kqb7viCV3isAL43dciOSog==} + engines: {node: '>=14'} + dev: true + /parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -3827,6 +3872,11 @@ packages: engines: {node: '>=8'} dev: true + /path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -4338,6 +4388,11 @@ packages: hasBin: true dev: true + /unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + dev: true + /update-browserslist-db@1.0.10(browserslist@4.21.4): resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} hasBin: true @@ -4487,3 +4542,8 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} dev: true + + /yocto-queue@1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + engines: {node: '>=12.20'} + dev: true From efc9f17486d4fc609ddba0fb517bdb9b9b450991 Mon Sep 17 00:00:00 2001 From: Stanislav Makarov Date: Thu, 21 Mar 2024 05:19:20 +0300 Subject: [PATCH 25/31] fix some linting errors --- src/deb/deb-builder.mts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index ebb40ee..784e96c 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -171,8 +171,8 @@ export class DebBuilder implements Deployer { const createFileOperation = this.packageCreator(deb.artifact.md5, debPath); - if(createFileOperation instanceof Promise) { - createFilePromise = createFileOperation + if (createFileOperation instanceof Promise) { + createFilePromise = createFileOperation; } }); }); From 9278fdacddc65e87d67b1426d077b3d6417945ad Mon Sep 17 00:00:00 2001 From: Stanislav Makarov Date: Thu, 21 Mar 2024 13:10:03 +0300 Subject: [PATCH 26/31] move DebBuilderConfig to deb-builder.mts --- src/deb/deb-builder-config.mts | 27 --------------------------- src/deb/deb-builder.mts | 29 +++++++++++++++++++++++++---- src/index.mts | 8 ++++++-- 3 files changed, 31 insertions(+), 33 deletions(-) delete mode 100644 src/deb/deb-builder-config.mts diff --git a/src/deb/deb-builder-config.mts b/src/deb/deb-builder-config.mts deleted file mode 100644 index 8969f9f..0000000 --- a/src/deb/deb-builder-config.mts +++ /dev/null @@ -1,27 +0,0 @@ -import type { Artifact } from '../artifact-provider.mjs'; - -export interface DebBuilderConfig { - out: string, - gpgKeyName: string; - applicationName: string; - origin: string; - repo: DebRepo; -} - -type Distribution = string; -type UbuntuComponentsEnum = 'main' | 'universe' | 'restricted' | 'multiverse'; - -export type UbuntuComponent = { - [key in UbuntuComponentsEnum]: string; -}; - -export interface DebDescriptor { - version: string, - artifact: Artifact -} - -export interface DebRepo { - [key: Distribution]: { - [key in keyof UbuntuComponent]?: DebDescriptor[] - } -} diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index 784e96c..480b857 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -5,11 +5,24 @@ import * as ini from 'ini'; import * as path from 'path'; import * as tar from 'tar'; +import type { Artifact, ArtifactProvider } from '../artifact-provider.mjs'; import { createDir, execToolToFile, removeDir } from '../fs.mjs'; -import type { DebBuilderConfig, DebDescriptor, DebRepo } from './deb-builder-config.mjs'; -import type { ArtifactProvider } from '../artifact-provider.mjs'; import type { Deployer } from '../deployer.mjs'; +type DebRepoDistribution = string; +type DebRepoComponent = string; + +export interface DebDescriptor { + version: string, + artifact: Artifact +} + +export interface DebRepo { + [key: DebRepoDistribution]: { + [key: DebRepoComponent]: DebDescriptor[] + } +} + const ReleaseFileTemplate = `Origin: $ORIGIN Label: Ubuntu/Debian @@ -39,8 +52,16 @@ function iterateDebs(repo: DebRepo, callback: (distribution: string, component: }); } +export interface Config { + out: string, + gpgKeyName: string; + applicationName: string; + origin: string; + repo: DebRepo; +} + export class DebBuilder implements Deployer { - private readonly config: DebBuilderConfig; + private readonly config: Config; private readonly artifactProvider: ArtifactProvider; private readonly packageCreator: (md5: string, path: string) => (Promise | void); @@ -50,7 +71,7 @@ export class DebBuilder implements Deployer { private readonly dists: string; private archesByDistComp: Map> = new Map(); - constructor(config: DebBuilderConfig, artifactProvider: ArtifactProvider, packageCreator: (md5: string, path: string) => (Promise | void)) { + constructor(config: Config, artifactProvider: ArtifactProvider, packageCreator: (md5: string, path: string) => (Promise | void)) { this.config = config; this.artifactProvider = artifactProvider; this.packageCreator = packageCreator; diff --git a/src/index.mts b/src/index.mts index a14dce5..e2929f8 100644 --- a/src/index.mts +++ b/src/index.mts @@ -2,8 +2,12 @@ import type { Config } from './config.mjs'; export type { Config }; export type { Artifact, ArtifactProvider } from './artifact-provider.mjs'; export type { ProviderType, ArtifactProviderConfig } from './artifact-provider-config.mjs'; -export type { DebBuilderConfig, DebDescriptor, DebRepo } from './deb/deb-builder-config.mjs'; -export { DebBuilder } from './deb/deb-builder.mjs'; +export { + type DebDescriptor, + type DebRepo, + type Config as DebBuilderConfig, + DebBuilder, +} from './deb/deb-builder.mjs'; export { default as JfrogArtifactProvider } from './jfrog/artifact-provider.mjs'; export { createMetapointerFile as createS3MetapointerFile } from './s3-metapointer.mjs'; From 01fa12bf1850a1bb48a1f9d79b4bf13c784f14bb Mon Sep 17 00:00:00 2001 From: Stanislav Makarov Date: Thu, 21 Mar 2024 13:24:40 +0300 Subject: [PATCH 27/31] rename path-containing properties in DebBuilder --- src/deb/deb-builder.mts | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index 480b857..cdb4433 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -65,10 +65,10 @@ export class DebBuilder implements Deployer { private readonly artifactProvider: ArtifactProvider; private readonly packageCreator: (md5: string, path: string) => (Promise | void); - private readonly root: string; - private readonly temp: string; - private readonly pool: string; - private readonly dists: string; + private readonly rootPath: string; + private readonly tempPath: string; + private readonly poolPath: string; + private readonly distsPath: string; private archesByDistComp: Map> = new Map(); constructor(config: Config, artifactProvider: ArtifactProvider, packageCreator: (md5: string, path: string) => (Promise | void)) { @@ -76,10 +76,10 @@ export class DebBuilder implements Deployer { this.artifactProvider = artifactProvider; this.packageCreator = packageCreator; - this.root = path.join(this.config.out); - this.temp = path.join(this.config.out, 'temp'); - this.pool = path.join(this.root, 'pool'); - this.dists = path.join(this.root, 'dists'); + this.rootPath = path.join(this.config.out); + this.tempPath = path.join(this.config.out, 'temp'); + this.poolPath = path.join(this.rootPath, 'pool'); + this.distsPath = path.join(this.rootPath, 'dists'); } public async plan(): Promise { @@ -87,7 +87,7 @@ export class DebBuilder implements Deployer { await this.dpkgScanpackages(); await this.makeRelease(); } finally { - removeDir(this.temp); + removeDir(this.tempPath); } } @@ -106,13 +106,14 @@ export class DebBuilder implements Deployer { .replace('$ARCH', arch) .replace('$COMPONENT', component); - const releaseFilePath = path.join(this.dists, distribution, 'Release'); - const releaseGpgFilePath = path.join(this.dists, distribution, 'Release.gpg'); - const inReleaseFilePath = path.join(this.dists, distribution, 'InRelease'); + const distributionPath = path.join(this.distsPath, distribution); + const releaseFilePath = path.join(distributionPath, 'Release'); + const releaseGpgFilePath = path.join(distributionPath, 'Release.gpg'); + const inReleaseFilePath = path.join(distributionPath, 'InRelease'); await fs.promises.writeFile(releaseFilePath, releaseContent); - await execToolToFile('apt-ftparchive', ['release', `${this.dists}/${distribution}`], releaseFilePath, true); + await execToolToFile('apt-ftparchive', ['release', distributionPath], releaseFilePath, true); await execToolToFile('gpg', ['--no-tty', '--default-key', this.config.gpgKeyName, '-abs', '-o', releaseGpgFilePath, releaseFilePath]); await execToolToFile('gpg', ['--no-tty', '--default-key', this.config.gpgKeyName, '--clearsign', '-o', inReleaseFilePath, releaseFilePath]); } @@ -137,7 +138,7 @@ export class DebBuilder implements Deployer { const controlTar = await this.artifactProvider.getArtifactContent(deb.artifact, controlTarRange); - const whereExtract = path.join(this.temp, `control-${deb.artifact.md5}`); + const whereExtract = path.join(this.tempPath, `control-${deb.artifact.md5}`); createDir(whereExtract); @@ -160,7 +161,7 @@ export class DebBuilder implements Deployer { this.archesByDistComp.set(`${distribution}/${component}`, new Set([arch])); } - const targetMetaPath = path.join(this.dists, + const targetMetaPath = path.join(this.distsPath, distribution, component, `binary-${arch}`, @@ -170,13 +171,13 @@ export class DebBuilder implements Deployer { removeDir(whereExtract); - const debPath = path.join(this.pool, + const debPath = path.join(this.poolPath, component, `${this.config.applicationName[0]}`, this.config.applicationName, distribution, this.debName(deb.version, arch)); - const relativeDebPath = path.relative(this.root, debPath); + const relativeDebPath = path.relative(this.rootPath, debPath); const debSize = controlTar.headers['content-range']?.split('/')[1]; const sha1 = controlTar.headers['x-checksum-sha1']; const sha256 = controlTar.headers['x-checksum-sha256']; @@ -219,8 +220,8 @@ export class DebBuilder implements Deployer { const compressPromises: Promise[] = []; iterateComponents(this.config.repo, (distribution, component) => { - const componentssRoot = path.join(this.dists, distribution, component); - const componentsByArch = fs.readdirSync(componentssRoot).map(dist => path.join(componentssRoot, dist)); + const componentRoot = path.join(this.distsPath, distribution, component); + const componentsByArch = fs.readdirSync(componentRoot).map(dist => path.join(componentRoot, dist)); componentsByArch.forEach(dist => { const targetPackagesFile = path.join(dist, 'Packages'); From 435e0121c11d2368508c132bdec0ca2d2897ffe1 Mon Sep 17 00:00:00 2001 From: Stanislav Makarov Date: Thu, 21 Mar 2024 13:35:02 +0300 Subject: [PATCH 28/31] use parseInt instead of Number constructor --- src/deb/deb-builder.mts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index cdb4433..e48b02e 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -130,16 +130,16 @@ export class DebBuilder implements Deployer { private async handleDeb(distribution: string, component: string, deb: DebDescriptor): Promise { const controlTarSizeRange = { start: 120, end: 129 }; - - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call - const controlTarSize = Number((await this.artifactProvider.getArtifactContent(deb.artifact, controlTarSizeRange)).read().toString() - .trim()); + const controlTarSizeString = + (await this.artifactProvider.getArtifactContent(deb.artifact, controlTarSizeRange)) + .read() + .toString() + .trim(); + const controlTarSize = parseInt(controlTarSizeString, 10); const controlTarRange = { start: 132, end: 131 + controlTarSize }; - const controlTar = await this.artifactProvider.getArtifactContent(deb.artifact, controlTarRange); const whereExtract = path.join(this.tempPath, `control-${deb.artifact.md5}`); - createDir(whereExtract); let createFilePromise: Promise | undefined = undefined; From efcba511bf60c48982753581132f2f3aba5216d9 Mon Sep 17 00:00:00 2001 From: Stanislav Makarov Date: Mon, 25 Mar 2024 18:34:10 +0300 Subject: [PATCH 29/31] style(debian): rename debName -> debFileName --- src/deb/deb-builder.mts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index e48b02e..760dda2 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -95,7 +95,7 @@ export class DebBuilder implements Deployer { console.log(this); } - private debName(version: string, arch: string): string { + private debFileName(version: string, arch: string): string { return `${this.config.applicationName}-${version}_${arch}.deb`; } @@ -165,7 +165,7 @@ export class DebBuilder implements Deployer { distribution, component, `binary-${arch}`, - `${this.debName(deb.version, arch)}.meta`); + `${this.debFileName(deb.version, arch)}.meta`); createDir(path.dirname(targetMetaPath)); fs.renameSync(path.join(whereExtract, 'control'), targetMetaPath); @@ -176,7 +176,7 @@ export class DebBuilder implements Deployer { `${this.config.applicationName[0]}`, this.config.applicationName, distribution, - this.debName(deb.version, arch)); + this.debFileName(deb.version, arch)); const relativeDebPath = path.relative(this.rootPath, debPath); const debSize = controlTar.headers['content-range']?.split('/')[1]; const sha1 = controlTar.headers['x-checksum-sha1']; From d8efcd7657146b1c49cec9596cae9879b311fcd9 Mon Sep 17 00:00:00 2001 From: Stanislav Makarov Date: Mon, 25 Mar 2024 23:17:08 +0300 Subject: [PATCH 30/31] chore: add more modules to test coverage ignore list --- src/index.spec.mts | 8 +++++++- src/jest.config.mjs | 8 ++++++++ src/repo.mts | 15 --------------- 3 files changed, 15 insertions(+), 16 deletions(-) delete mode 100644 src/repo.mts diff --git a/src/index.spec.mts b/src/index.spec.mts index c52d111..4d7db8d 100644 --- a/src/index.spec.mts +++ b/src/index.spec.mts @@ -1,6 +1,7 @@ import { describe, expect, it } from '@jest/globals'; import { apply, plan } from './index.mjs'; +import type { Deployer } from './deployer.mjs'; describe('apply', () => { it('should return undefined', () => { @@ -10,6 +11,11 @@ describe('apply', () => { describe('plan', () => { it('should return undefined', async() => { - expect(await plan({ deployers: [] })).toBe(undefined); + const dummyDeployer: Deployer = { + plan: () => Promise.resolve(), + // eslint-disable-next-line no-empty-function + apply: () => {}, + }; + expect(await plan({ deployers: [dummyDeployer] })).toBe(undefined); }); }); diff --git a/src/jest.config.mjs b/src/jest.config.mjs index 36e15e3..eda3d98 100644 --- a/src/jest.config.mjs +++ b/src/jest.config.mjs @@ -9,8 +9,16 @@ export default { collectCoverageFrom: ['**/*.mts'], coveragePathIgnorePatterns: [ + 'src/artifact-provider-config.mts', + 'src/artifact-provider.mts', 'src/cli.mts', 'src/config.mts', + 'src/deb/*', + 'src/deployer.mts', + 'src/fs.mts', + 'src/jfrog/*', + 'src/http.mts', + 'src/s3-metapointer.mts', 'src/utils.mts', ], diff --git a/src/repo.mts b/src/repo.mts deleted file mode 100644 index 74225a6..0000000 --- a/src/repo.mts +++ /dev/null @@ -1,15 +0,0 @@ -export interface Package { - version: string, - buildNumber: string -} - -export interface Packages { - packages: Package[], - highest: Package, -} - -export type Channel = string; -export type Repo = { - channel: Channel, - packages: Packages -}[] From 7511a0fe6009ed69702e95ba8c088ffa31c21924 Mon Sep 17 00:00:00 2001 From: Stanislav Makarov Date: Wed, 27 Mar 2024 06:12:46 +0300 Subject: [PATCH 31/31] fix(debian): get package version from Version field in control file --- src/deb/deb-builder.mts | 28 ++++++++++++---------------- src/index.mts | 1 - 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/deb/deb-builder.mts b/src/deb/deb-builder.mts index 760dda2..1464a4b 100644 --- a/src/deb/deb-builder.mts +++ b/src/deb/deb-builder.mts @@ -12,14 +12,9 @@ import type { Deployer } from '../deployer.mjs'; type DebRepoDistribution = string; type DebRepoComponent = string; -export interface DebDescriptor { - version: string, - artifact: Artifact -} - export interface DebRepo { [key: DebRepoDistribution]: { - [key: DebRepoComponent]: DebDescriptor[] + [key: DebRepoComponent]: Artifact[] } } @@ -30,7 +25,7 @@ Architecture: $ARCH Component: $COMPONENT Codename: $DISTRIBUTION\n`; -function iterateComponents(repo: DebRepo, callback: (distribution: string, component: string, deb: DebDescriptor[]) => void): void { +function iterateComponents(repo: DebRepo, callback: (distribution: string, component: string, deb: Artifact[]) => void): void { const distributions = Object.keys(repo); distributions.forEach(distribution => { @@ -44,8 +39,8 @@ function iterateComponents(repo: DebRepo, callback: (distribution: string, compo }); } -function iterateDebs(repo: DebRepo, callback: (distribution: string, component: string, deb: DebDescriptor) => void): void { - iterateComponents(repo, (distribution: string, component: string, debs: DebDescriptor[]) => { +function iterateDebs(repo: DebRepo, callback: (distribution: string, component: string, deb: Artifact) => void): void { + iterateComponents(repo, (distribution: string, component: string, debs: Artifact[]) => { debs.forEach(deb => { callback(distribution, component, deb); }); @@ -128,18 +123,18 @@ export class DebBuilder implements Deployer { await Promise.all(promises); } - private async handleDeb(distribution: string, component: string, deb: DebDescriptor): Promise { + private async handleDeb(distribution: string, component: string, deb: Artifact): Promise { const controlTarSizeRange = { start: 120, end: 129 }; const controlTarSizeString = - (await this.artifactProvider.getArtifactContent(deb.artifact, controlTarSizeRange)) + (await this.artifactProvider.getArtifactContent(deb, controlTarSizeRange)) .read() .toString() .trim(); const controlTarSize = parseInt(controlTarSizeString, 10); const controlTarRange = { start: 132, end: 131 + controlTarSize }; - const controlTar = await this.artifactProvider.getArtifactContent(deb.artifact, controlTarRange); + const controlTar = await this.artifactProvider.getArtifactContent(deb, controlTarRange); - const whereExtract = path.join(this.tempPath, `control-${deb.artifact.md5}`); + const whereExtract = path.join(this.tempPath, `control-${deb.md5}`); createDir(whereExtract); let createFilePromise: Promise | undefined = undefined; @@ -152,6 +147,7 @@ export class DebBuilder implements Deployer { const controlMetaContent = fs.readFileSync(path.join(whereExtract, 'control'), 'utf-8').replaceAll(':', '='); const controlMeta = ini.parse(controlMetaContent); const arch = controlMeta['Architecture']; + const version = controlMeta['Version']; const archesSet = this.archesByDistComp.get(`${distribution}/${component}`); @@ -165,7 +161,7 @@ export class DebBuilder implements Deployer { distribution, component, `binary-${arch}`, - `${this.debFileName(deb.version, arch)}.meta`); + `${this.debFileName(version, arch)}.meta`); createDir(path.dirname(targetMetaPath)); fs.renameSync(path.join(whereExtract, 'control'), targetMetaPath); @@ -176,7 +172,7 @@ export class DebBuilder implements Deployer { `${this.config.applicationName[0]}`, this.config.applicationName, distribution, - this.debFileName(deb.version, arch)); + this.debFileName(version, arch)); const relativeDebPath = path.relative(this.rootPath, debPath); const debSize = controlTar.headers['content-range']?.split('/')[1]; const sha1 = controlTar.headers['x-checksum-sha1']; @@ -191,7 +187,7 @@ export class DebBuilder implements Deployer { fs.promises.appendFile(targetMetaPath, dataToAppend).then(() => resolve()); - const createFileOperation = this.packageCreator(deb.artifact.md5, debPath); + const createFileOperation = this.packageCreator(deb.md5, debPath); if (createFileOperation instanceof Promise) { createFilePromise = createFileOperation; diff --git a/src/index.mts b/src/index.mts index e2929f8..2a8ffa2 100644 --- a/src/index.mts +++ b/src/index.mts @@ -3,7 +3,6 @@ export type { Config }; export type { Artifact, ArtifactProvider } from './artifact-provider.mjs'; export type { ProviderType, ArtifactProviderConfig } from './artifact-provider-config.mjs'; export { - type DebDescriptor, type DebRepo, type Config as DebBuilderConfig, DebBuilder,