From c971c879cc19503df07c7b434775aa69c5d1c928 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 3 May 2021 10:45:25 +0300 Subject: [PATCH 01/14] ci: Reinstate lintin and make it automatic --- .github/workflows/build.yml | 6 +- .github/workflows/lint.yml | 26 ++++ .github/workflows/release.yml | 2 +- .prettierignore | 3 + .prettierrc | 5 +- package.json | 13 +- yarn.lock | 271 ++-------------------------------- 7 files changed, 47 insertions(+), 279 deletions(-) create mode 100644 .github/workflows/lint.yml create mode 100644 .prettierignore diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a6151816..ee7ed997 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: 'Build / Test / Artifacts' +name: "Build / Test / Artifacts" on: push: branches: @@ -11,13 +11,13 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: ['10', '12', '14', '16'] + node: ["10", "12", "14", "16"] name: Node ${{ matrix.node }} steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '${{ matrix.node }}' + node-version: "${{ matrix.node }}" - uses: actions/cache@v2 id: cache with: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..9f0082f9 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,26 @@ +name: "Lint" +on: + pull_request: + +jobs: + lint: + name: Lint fixes + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: volta-cli/action@v1 + - uses: actions/cache@v2 + id: cache + with: + path: node_modules + key: ${{ runner.os }}-${{ hashFiles('package.json', 'yarn.lock') }} + - name: Install Dependencies + if: steps.cache.outputs.cache-hit != 'true' + run: yarn install --frozen-lockfile + - name: Lint + run: yarn lint + - name: Save lint fixes + run: > + git diff --quiet || + git commit -anm 'ref: Lint fixes' && + git push diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d5f923b3..32e5654e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ on: jobs: release: runs-on: ubuntu-latest - name: 'Release a new version' + name: "Release a new version" steps: - uses: actions/checkout@v2 with: diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..ef229ed3 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +coverage/ +dist/ +node_modules/ diff --git a/.prettierrc b/.prettierrc index c6a1376d..0967ef42 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1 @@ -{ - "trailingComma": "es5", - "singleQuote": true -} +{} diff --git a/package.json b/package.json index 96915ceb..9e6ad687 100644 --- a/package.json +++ b/package.json @@ -65,12 +65,10 @@ "lodash": "4.17.19", "mkdirp": "0.5.1", "mustache": "3.0.1", - "npm-run-all": "^4.1.3", "nvar": "1.3.1", "once": "1.4.0", "ora": "2.1.0", - "prettier": "^1.19.1", - "prettier-check": "^2.0.0", + "prettier": "^2.2.1", "request": "2.88.0", "rimraf": "2.7.1", "shell-quote": "1.6.1", @@ -88,15 +86,10 @@ "build:fat": "yarn run compile-config-schema && tsc -p tsconfig.build.json", "build:watch": "yarn run compile-config-schema && tsc -p tsconfig.build.json --watch", "build": "yarn compile-config-schema && esbuild src/index.ts --bundle --platform=node --target=node10.8 --outfile=dist/craft --minify", - "precli": "run-s build", + "precli": "build", "cli": "node dist/craft", "clean": "rimraf dist coverage", - "lint": "run-s lint:prettier lint:eslint", - "lint:prettier": "prettier-check 'src/**/*.ts'", - "lint:eslint": "eslint src --ext .ts --format stylish", - "fix": "run-s fix:tslint fix:prettier", - "fix:prettier": "prettier --write 'src/**/*.ts'", - "fix:eslint": "eslint src --ext .ts --fix --format stylish", + "lint": "prettier --write .", "test": "jest", "test:watch": "jest --watch --notify", "compile-config-schema": "node ./scripts/config-json-schema-to-ts.js" diff --git a/yarn.lock b/yarn.lock index 2782a1d3..16094fe6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2162,14 +2162,6 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -call-bind@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - call-me-maybe@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" @@ -2209,7 +2201,7 @@ chainsaw@~0.1.0: dependencies: traverse ">=0.3.0 <0.4" -chalk@2.4.1, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.1, chalk@^2.3.2, chalk@^2.4.1: +chalk@2.4.1, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.1, chalk@^2.3.2: version "2.4.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== @@ -2431,16 +2423,7 @@ core-util-is@1.0.2, core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -cross-spawn@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^6.0.0, cross-spawn@^6.0.5: +cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -2564,13 +2547,6 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" -define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" @@ -2702,33 +2678,6 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.18.0-next.1: - version "1.18.0-next.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68" - integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.2" - is-negative-zero "^2.0.0" - is-regex "^1.1.1" - object-inspect "^1.8.0" - object-keys "^1.1.1" - object.assign "^4.1.1" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: version "0.10.53" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" @@ -2928,19 +2877,6 @@ exec-sh@^0.3.2: resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== -execa@^0.6.0: - version "0.6.3" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.6.3.tgz#57b69a594f081759c69e5370f0d17b9cb11658fe" - integrity sha1-V7aaWU8IF1nGnlNw8NF7nLEWWP4= - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - execa@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" @@ -3276,15 +3212,6 @@ get-caller-file@^2.0.0, get-caller-file@^2.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.2.tgz#6820da226e50b24894e08859469dc68361545d49" - integrity sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -3295,11 +3222,6 @@ get-stdin@^6.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - get-stream@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -3427,11 +3349,6 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" - integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== - has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -3617,11 +3534,6 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= -is-callable@^1.1.4, is-callable@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9" - integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA== - is-ci@^1.1.0: version "1.2.1" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" @@ -3657,11 +3569,6 @@ is-data-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== - is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" @@ -3724,11 +3631,6 @@ is-glob@^4.0.0, is-glob@^4.0.1: dependencies: is-extglob "^2.1.1" -is-negative-zero@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" - integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== - is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -3768,13 +3670,6 @@ is-promise@^2.2.2: resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== -is-regex@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" - integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== - dependencies: - has-symbols "^1.0.1" - is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -3785,13 +3680,6 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== -is-symbol@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== - dependencies: - has-symbols "^1.0.1" - is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -4320,11 +4208,6 @@ json-bigint@^1.0.0: dependencies: bignumber.js "^9.0.0" -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" @@ -4466,16 +4349,6 @@ listenercount@~1.0.1: resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" integrity sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc= -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - locate-path@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" @@ -4525,14 +4398,6 @@ log-symbols@^2.2.0: dependencies: chalk "^2.0.1" -lru-cache@^4.0.1: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -4607,11 +4472,6 @@ memoizee@^0.4.14: next-tick "^1.1.0" timers-ext "^0.1.7" -memorystream@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" - integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= - merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -4821,7 +4681,7 @@ node-notifier@^8.0.0: uuid "^8.3.0" which "^2.0.2" -normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: +normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== @@ -4843,21 +4703,6 @@ normalize-path@^3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -npm-run-all@^4.1.3: - version "4.1.5" - resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" - integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ== - dependencies: - ansi-styles "^3.2.1" - chalk "^2.4.1" - cross-spawn "^6.0.5" - memorystream "^0.3.1" - minimatch "^3.0.4" - pidtree "^0.3.0" - read-pkg "^3.0.0" - shell-quote "^1.6.1" - string.prototype.padend "^3.0.0" - npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -4901,16 +4746,6 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.8.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" - integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== - -object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" @@ -4918,16 +4753,6 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.assign@^4.1.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" @@ -5060,14 +4885,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - parse-json@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.1.0.tgz#f96088cdf24a8faa9aea9a009f2d9d942c999646" @@ -5113,13 +4930,6 @@ path-parse@^1.0.6: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -5130,16 +4940,6 @@ picomatch@^2.0.4, picomatch@^2.0.5: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== -pidtree@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" - integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - pirates@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" @@ -5169,18 +4969,16 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -prettier-check@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prettier-check/-/prettier-check-2.0.0.tgz#edd086ee12d270579233ccb136a16e6afcfba1ae" - integrity sha512-HZG53XQTJ9Cyi5hi1VFVVFxdlhITJybpZAch3ib9KqI05VUxV+F5Hip0GhSWRItrlDzVyqjSoDQ9KqIn7AHYyw== - dependencies: - execa "^0.6.0" - -prettier@^1.14.2, prettier@^1.19.1: +prettier@^1.14.2: version "1.19.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== +prettier@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" + integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== + pretty-format@^26.0.0, pretty-format@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" @@ -5209,11 +5007,6 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - psl@^1.1.24, psl@^1.1.28: version "1.8.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" @@ -5282,15 +5075,6 @@ read-pkg-up@^7.0.1: read-pkg "^5.2.0" type-fest "^0.8.1" -read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - read-pkg@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" @@ -5617,7 +5401,7 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote@1.6.1, shell-quote@^1.6.1: +shell-quote@1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" integrity sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c= @@ -5881,31 +5665,6 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string.prototype.padend@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.1.tgz#824c84265dbac46cade2b957b38b6a5d8d1683c5" - integrity sha512-eCzTASPnoCr5Ht+Vn1YXgm8SB015hHKgEIMu9Nr9bQmLhRBxKRfmzSj/IQsxDFc8JInJDDFA0qXwK+xxI7wDkg== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - -string.prototype.trimend@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz#a22bd53cca5c7cf44d7c9d5c732118873d6cd18b" - integrity sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - -string.prototype.trimstart@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz#9b4cb590e123bb36564401d59824298de50fd5aa" - integrity sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - string_decoder@^1.1.1, string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -5934,11 +5693,6 @@ strip-ansi@^6.0.0: dependencies: ansi-regex "^5.0.0" -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - strip-bom@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" @@ -6580,11 +6334,6 @@ y18n@^4.0.0: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4" integrity sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ== -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - yallist@^3.0.0, yallist@^3.0.2: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" From a96261a3c95445d8483e4bccf11f8cb0673417b4 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 3 May 2021 10:49:02 +0300 Subject: [PATCH 02/14] set git identity for lint fixer --- .github/workflows/lint.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 9f0082f9..f96569f6 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -21,6 +21,9 @@ jobs: run: yarn lint - name: Save lint fixes run: > + GIT_COMMITTER_NAME=getsentry-bot + GIT_AUTHOR_NAME=getsentry-bot + EMAIL=bot@getsentry.com git diff --quiet || git commit -anm 'ref: Lint fixes' && git push From 40ccde5956c4a586feaeb7f583f87374932a32d3 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 3 May 2021 10:51:02 +0300 Subject: [PATCH 03/14] use git config --- .github/workflows/lint.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f96569f6..c5d5ddda 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -21,9 +21,8 @@ jobs: run: yarn lint - name: Save lint fixes run: > - GIT_COMMITTER_NAME=getsentry-bot - GIT_AUTHOR_NAME=getsentry-bot - EMAIL=bot@getsentry.com + git config user.email "bot@getsentry.com" && + git config user.name "getsentry-bot" && git diff --quiet || git commit -anm 'ref: Lint fixes' && git push From 060fef57a043a5aa41a0fa5a071b7cdf4bcc800b Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 3 May 2021 10:54:21 +0300 Subject: [PATCH 04/14] fix fetch-depth --- .github/workflows/lint.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c5d5ddda..e484dcd2 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,6 +8,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + with: + # Full git history is needed to push back the fixes + fetch-depth: 0 - uses: volta-cli/action@v1 - uses: actions/cache@v2 id: cache From dff8ee9f9de36f22d50e4799c5577bb72d3322c7 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 3 May 2021 11:00:44 +0300 Subject: [PATCH 05/14] use head ref --- .github/workflows/lint.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e484dcd2..0bfd4b0d 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,8 +9,7 @@ jobs: steps: - uses: actions/checkout@v2 with: - # Full git history is needed to push back the fixes - fetch-depth: 0 + ref: ${{ github.event.pull_request.head.ref }} - uses: volta-cli/action@v1 - uses: actions/cache@v2 id: cache From 2bacdc31ee4607ad46e2afe432ca58420984c2c6 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Mon, 3 May 2021 08:01:46 +0000 Subject: [PATCH 06/14] ref: Lint fixes --- .craft.yml | 10 +- .eslintrc.js | 18 +- CHANGELOG.md | 1 + README.md | 21 +- action.yml | 18 +- cloudbuild.yaml | 44 ++-- docs/_site/assets/main.css | 96 ++++++--- docs/_site/index.html | 4 +- jest.config.js | 8 +- scripts/config-json-schema-to-ts.js | 16 +- src/__mocks__/@aws-sdk/client-lambda.ts | 2 +- src/__mocks__/fs.ts | 2 +- src/__mocks__/logger.ts | 6 +- src/__tests__/config.test.ts | 40 ++-- src/__tests__/index.test.ts | 2 +- src/artifact_providers/base.ts | 20 +- src/artifact_providers/gcs.ts | 14 +- src/artifact_providers/github.ts | 40 ++-- src/artifact_providers/none.ts | 6 +- src/artifact_providers/zeus.ts | 30 +-- src/commands/__tests__/prepare.test.ts | 28 +-- src/commands/__tests__/publish.test.ts | 32 +-- src/commands/artifacts.ts | 22 +- src/commands/artifacts_cmds/download.ts | 58 ++--- src/commands/artifacts_cmds/list.ts | 26 +-- src/commands/prepare.ts | 136 ++++++------ src/commands/publish.ts | 200 +++++++++--------- src/commands/targets.ts | 12 +- src/config.ts | 68 +++--- src/index.ts | 50 ++--- src/logger.ts | 10 +- src/schemas/projectConfig.schema.ts | 134 ++++++------ src/schemas/project_config.ts | 18 +- src/status_providers/base.ts | 22 +- src/status_providers/github.ts | 50 ++--- src/status_providers/zeus.ts | 6 +- src/stores/__tests__/zeus.test.ts | 82 +++---- src/stores/zeus.ts | 44 ++-- src/targets/__tests__/awsLambda.test.ts | 70 +++--- src/targets/__tests__/crates.test.ts | 36 ++-- src/targets/__tests__/index.test.ts | 16 +- src/targets/awsLambdaLayer.ts | 90 ++++---- src/targets/base.ts | 16 +- src/targets/brew.ts | 50 ++--- src/targets/cocoapods.ts | 48 ++--- src/targets/crates.ts | 86 ++++---- src/targets/docker.ts | 40 ++-- src/targets/gcs.ts | 46 ++-- src/targets/gem.ts | 26 +-- src/targets/ghPages.ts | 70 +++--- src/targets/github.ts | 62 +++--- src/targets/index.ts | 40 ++-- src/targets/npm.ts | 76 +++---- src/targets/nuget.ts | 36 ++-- src/targets/pypi.ts | 28 +-- src/targets/registry.ts | 88 ++++---- src/types/consola.d.ts | 2 +- src/types/mustache.d.ts | 2 +- src/types/nvar.ts | 2 +- src/types/split.d.ts | 2 +- src/types/unzipper.ts | 2 +- src/utils/__fixtures__/gcsApi.ts | 56 ++--- src/utils/__fixtures__/gcsFileObj.ts | 138 ++++++------ src/utils/__tests__/async.test.ts | 96 ++++----- .../__tests__/awsLambdaLayerManager.test.ts | 58 ++--- src/utils/__tests__/changes.test.ts | 110 +++++----- src/utils/__tests__/env.test.ts | 182 ++++++++-------- src/utils/__tests__/errors.test.ts | 22 +- src/utils/__tests__/files.test.ts | 58 ++--- src/utils/__tests__/filters.test.ts | 28 +-- src/utils/__tests__/gcsAPI.test.ts | 138 ++++++------ src/utils/__tests__/githubApi.test.ts | 78 +++---- src/utils/__tests__/helpers.test.ts | 22 +- src/utils/__tests__/noInput.test.ts | 20 +- src/utils/__tests__/objects.test.ts | 8 +- src/utils/__tests__/packagePath.test.ts | 46 ++-- src/utils/__tests__/strings.test.ts | 84 ++++---- src/utils/__tests__/system.test.ts | 118 +++++------ src/utils/__tests__/version.test.ts | 128 +++++------ src/utils/async.ts | 4 +- src/utils/awsLambdaLayerManager.ts | 38 ++-- src/utils/changes.ts | 20 +- src/utils/checksum.ts | 8 +- src/utils/env.ts | 18 +- src/utils/errors.ts | 24 +-- src/utils/files.ts | 26 +-- src/utils/filters.ts | 4 +- src/utils/gcsApi.ts | 28 +-- src/utils/githubApi.ts | 40 ++-- src/utils/helpers.ts | 2 +- src/utils/noInput.ts | 4 +- src/utils/packagePath.ts | 20 +- src/utils/registry.ts | 20 +- src/utils/sentry.ts | 36 ++-- src/utils/strings.ts | 14 +- src/utils/symlink.ts | 12 +- src/utils/system.ts | 118 ++++++----- src/utils/version.ts | 8 +- tsconfig.build.json | 10 +- tsconfig.json | 10 +- 100 files changed, 2115 insertions(+), 2069 deletions(-) diff --git a/.craft.yml b/.craft.yml index b2be7983..f791c243 100644 --- a/.craft.yml +++ b/.craft.yml @@ -1,4 +1,4 @@ -minVersion: '0.21.0' +minVersion: "0.21.0" github: owner: getsentry repo: craft @@ -14,18 +14,18 @@ targets: paths: - path: /craft/{{version}}/ metadata: - cacheControl: 'public, max-age=2592000' + cacheControl: "public, max-age=2592000" - path: /craft/latest/ metadata: - cacheControl: 'public, max-age=300' + cacheControl: "public, max-age=300" - name: registry type: app - urlTemplate: 'https://downloads.sentry-cdn.com/craft/{{version}}/{{file}}' + urlTemplate: "https://downloads.sentry-cdn.com/craft/{{version}}/{{file}}" checksums: - algorithm: sha256 format: hex config: - canonical: 'app:craft' + canonical: "app:craft" - name: docker source: us.gcr.io/sentryio/craft target: getsentry/craft diff --git a/.eslintrc.js b/.eslintrc.js index 4f3853a3..6efc033a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,18 +4,18 @@ module.exports = { es2017: true, node: true, }, - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint'], + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint"], extends: [ - 'prettier', - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'prettier/@typescript-eslint', + "prettier", + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "prettier/@typescript-eslint", ], rules: { - '@typescript-eslint/no-explicit-any': 'off', - 'no-constant-condition': ['error', { checkLoops: false }], + "@typescript-eslint/no-explicit-any": "off", + "no-constant-condition": ["error", { checkLoops: false }], // Make sure variables marked with _ are ignored (ex. _varName) - '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], + "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], }, }; diff --git a/CHANGELOG.md b/CHANGELOG.md index fa3606c9..d9a01f33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ `statusProvider` and `artifactProvider` to `github` if `minVersion` is greater or equal to `0.21.0`. If your craft configuration file does not set these providers explicitly, you can keep the old behavior by modifying your config: + ```yaml minVersion: 0.21.0 artifactProvider: diff --git a/README.md b/README.md index 02d0a16f..bbaba12d 100644 --- a/README.md +++ b/README.md @@ -354,7 +354,7 @@ your configuration. **Example:** ```yaml -minVersion: '0.5.0' +minVersion: "0.5.0" ``` ### Required Files @@ -381,7 +381,7 @@ By default, it will use GitHub but you can add more providers if needed. | Option | Description | | -------- | -------------------------------------------------------------------------------------------------- | -| `name` | Name of the status provider: either `github` (default) or `zeus` (deprecated) | +| `name` | Name of the status provider: either `github` (default) or `zeus` (deprecated) | | `config` | In case of `github`: may include `contexts` key that contains a list of required contexts (checks) | **Example:** @@ -434,13 +434,13 @@ targets: - algorithm: sha384 format: base64 config: - canonical: 'npm:@sentry/browser' + canonical: "npm:@sentry/browser" - name: registry id: node type: sdk onlyIfPresent: /^sentry-node-.*\.tgz$/ config: - canonical: 'npm:@sentry/node' + canonical: "npm:@sentry/node" ``` ### Per-target options @@ -783,13 +783,13 @@ targets: - name: registry type: sdk config: - canonical: 'npm:@sentry/browser' + canonical: "npm:@sentry/browser" - name: registry type: app - urlTemplate: 'https://example.com/{{version}}/{{file}}' + urlTemplate: "https://example.com/{{version}}/{{file}}" config: - canonical: 'npm:@sentry/browser' + canonical: "npm:@sentry/browser" checksums: - algorithm: sha256 format: hex @@ -955,9 +955,12 @@ Here is how you can integrate your GitHub project with `craft`: - The name of the artifacts is very important and needs to be `name: ${{ github.sha }}`. Craft uses this as a unique id to fetch the artifacts. - Keep in mind that this action maintains the folder structure and zips everything together. Craft will download the zip and recursively walk it to find all assets. + 3. Add `.craft.yml` configuration file to your project - - List there all the targets you want to publish to - - Configure additional options (changelog management policy, tag prefix, etc.) + +- List there all the targets you want to publish to +- Configure additional options (changelog management policy, tag prefix, etc.) + 4. Add a [pre-release script](#pre-release-version-bumping-script-conventions) to your project. 5. Get various [configuration tokens](#global-configuration) 6. Run `craft prepare --publish` and profit! diff --git a/action.yml b/action.yml index f0752f33..ab31f28d 100644 --- a/action.yml +++ b/action.yml @@ -1,22 +1,22 @@ -name: 'Craft' -description: 'Use getsentry/craft to publish your project' +name: "Craft" +description: "Use getsentry/craft to publish your project" inputs: action: - description: 'The action to take. Can be either prepare or publish' + description: "The action to take. Can be either prepare or publish" required: true - default: '--help' + default: "--help" version: - description: 'The version number for the new release' + description: "The version number for the new release" required: true no_merge: - description: 'Do not merge the release branch after publishing' + description: "Do not merge the release branch after publishing" required: false keep_branch: - description: 'Do not remove release branch after merging it' + description: "Do not remove release branch after merging it" required: false runs: - using: 'docker' - image: 'docker://getsentry/craft' + using: "docker" + image: "docker://getsentry/craft" args: - ${{ inputs.action }} - ${{ inputs.version }} diff --git a/cloudbuild.yaml b/cloudbuild.yaml index c91d5893..dea4f163 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -1,33 +1,33 @@ steps: - - name: 'gcr.io/kaniko-project/executor:v1.5.1' + - name: "gcr.io/kaniko-project/executor:v1.5.1" args: - - '--cache=true' - - '--use-new-run' - - '--build-arg' - - 'SOURCE_COMMIT=$COMMIT_SHA' - - '--destination=us.gcr.io/$PROJECT_ID/craft:builder-$COMMIT_SHA' - - '-f' - - 'builder.dockerfile' - - name: 'us.gcr.io/$PROJECT_ID/craft:builder-$COMMIT_SHA' - - name: 'gcr.io/kaniko-project/executor:v1.5.1' + - "--cache=true" + - "--use-new-run" + - "--build-arg" + - "SOURCE_COMMIT=$COMMIT_SHA" + - "--destination=us.gcr.io/$PROJECT_ID/craft:builder-$COMMIT_SHA" + - "-f" + - "builder.dockerfile" + - name: "us.gcr.io/$PROJECT_ID/craft:builder-$COMMIT_SHA" + - name: "gcr.io/kaniko-project/executor:v1.5.1" args: - - '--cache=true' - - '--use-new-run' - - '--build-arg' - - 'SOURCE_COMMIT=$COMMIT_SHA' - - '--destination=us.gcr.io/$PROJECT_ID/craft:$COMMIT_SHA' + - "--cache=true" + - "--use-new-run" + - "--build-arg" + - "SOURCE_COMMIT=$COMMIT_SHA" + - "--destination=us.gcr.io/$PROJECT_ID/craft:$COMMIT_SHA" timeout: 900s # Smoke tests - - name: 'us.gcr.io/$PROJECT_ID/craft:$COMMIT_SHA' + - name: "us.gcr.io/$PROJECT_ID/craft:$COMMIT_SHA" args: - - '--help' + - "--help" timeout: 60s - - name: 'gcr.io/cloud-builders/docker' - secretEnv: ['DOCKER_PASSWORD'] - entrypoint: 'bash' + - name: "gcr.io/cloud-builders/docker" + secretEnv: ["DOCKER_PASSWORD"] + entrypoint: "bash" args: - - '-e' - - '-c' + - "-e" + - "-c" - | # Only push to Docker Hub from master [ "$BRANCH_NAME" != "master" ] && exit 0 diff --git a/docs/_site/assets/main.css b/docs/_site/assets/main.css index 48c73199..443df7af 100644 --- a/docs/_site/assets/main.css +++ b/docs/_site/assets/main.css @@ -1,15 +1,18 @@ body { - font-family: 'Oxygen', serif; + font-family: "Oxygen", serif; color: #46433a; - background-color: #fcfcfc; } + background-color: #fcfcfc; +} header, main { - padding: 0 20px; } + padding: 0 20px; +} /* ** wrapper div for both header and main ** */ .wrapper { - margin-top: 10%; } + margin-top: 10%; +} /* ** anchor tags ** */ a:link, @@ -17,72 +20,104 @@ a:visited, a:hover, a:active { color: #ce534d; - text-decoration: none; } + text-decoration: none; +} a:hover { - text-decoration: underline; } + text-decoration: underline; +} /* ** main content list ** */ .main-list-item { font-weight: bold; font-size: 1.2em; - margin: 0.8em 0; } + margin: 0.8em 0; +} - /* override the left margin added by font awesome for the main content list, +/* override the left margin added by font awesome for the main content list, since it must be aligned with the content */ .fa-ul.main-list { - margin-left: 0; } + margin-left: 0; +} /* list icons */ .main-list-item-icon { width: 36px; - color: #46433a; } + color: #46433a; +} /* ** logo ** */ .logo-container { - text-align: center; } + text-align: center; +} .logo { width: 160px; height: 160px; display: inline-block; background-size: cover; - border: 2px solid #fcfcfc; } + border: 2px solid #fcfcfc; +} /* ** author ** */ .author-container h1 { font-size: 1.6em; margin-top: 0; margin-bottom: 0; - text-align: center; } + text-align: center; +} /* ** tagline ** */ .tagline-container p { font-size: 1.3em; text-align: center; - margin-bottom: 2em; } + margin-bottom: 2em; +} /* **** */ hr { border: 0; height: 1px; - background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0), #46433a, rgba(0, 0, 0, 0)); - background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0), #46433a, rgba(0, 0, 0, 0)); - background-image: -ms-linear-gradient(left, rgba(0, 0, 0, 0), #46433a, rgba(0, 0, 0, 0)); - background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0), #46433a, rgba(0, 0, 0, 0)); } + background-image: -webkit-linear-gradient( + left, + rgba(0, 0, 0, 0), + #46433a, + rgba(0, 0, 0, 0) + ); + background-image: -moz-linear-gradient( + left, + rgba(0, 0, 0, 0), + #46433a, + rgba(0, 0, 0, 0) + ); + background-image: -ms-linear-gradient( + left, + rgba(0, 0, 0, 0), + #46433a, + rgba(0, 0, 0, 0) + ); + background-image: -o-linear-gradient( + left, + rgba(0, 0, 0, 0), + #46433a, + rgba(0, 0, 0, 0) + ); +} /* ** footer ** */ footer { position: fixed; bottom: 0; right: 0; - height: 20px; } + height: 20px; +} .poweredby { - font-family: 'Arial Narrow', Arial; + font-family: "Arial Narrow", Arial; font-size: 0.6em; line-height: 0.6em; - padding: 0 5px; } + padding: 0 5px; +} /* ** media queries ** */ /* X-Small devices (phones, 480px and up) */ @@ -90,27 +125,34 @@ footer { /* wrapper stays 480px wide past 480px wide and is kept centered */ .wrapper { width: 480px; - margin: 10% auto 0 auto; } } + margin: 10% auto 0 auto; + } +} /* All other devices (768px and up) */ @media (min-width: 768px) { /* past 768px the layout is changed and the wrapper has a fixed width of 760px to accomodate both the header column and the content column */ .wrapper { - width: 760px; } + width: 760px; + } - /* the header column stays left and has a dynamic width with all contents + /* the header column stays left and has a dynamic width with all contents aligned right */ header { float: left; width: 46%; - text-align: right; } + text-align: right; + } .author-container h1, .logo-container, .tagline-container p { - text-align: right; } + text-align: right; + } main { width: 46%; margin-left: 54%; - padding: 0; } } + padding: 0; + } +} diff --git a/docs/_site/index.html b/docs/_site/index.html index 58f01d32..020b0e19 100644 --- a/docs/_site/index.html +++ b/docs/_site/index.html @@ -43,7 +43,9 @@ diff --git a/jest.config.js b/jest.config.js index 79317ff0..03706c4f 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,6 @@ module.exports = { - preset: 'ts-jest', - testEnvironment: 'node', - testPathIgnorePatterns: ['/dist/', '/node_modules/'], - modulePathIgnorePatterns: ['/dist/'], + preset: "ts-jest", + testEnvironment: "node", + testPathIgnorePatterns: ["/dist/", "/node_modules/"], + modulePathIgnorePatterns: ["/dist/"], }; diff --git a/scripts/config-json-schema-to-ts.js b/scripts/config-json-schema-to-ts.js index 7e980ff7..14bd13f2 100644 --- a/scripts/config-json-schema-to-ts.js +++ b/scripts/config-json-schema-to-ts.js @@ -1,19 +1,19 @@ /** * Convert JSON schema for project configuration to a set of TypeScript interfaces */ -const fs = require('fs'); -const json2ts = require('json-schema-to-typescript'); +const fs = require("fs"); +const json2ts = require("json-schema-to-typescript"); process.chdir(__dirname); -const jsonInputPath = '../src/schemas/projectConfig.schema.ts'; -const tsOutputPath = '../src/schemas/project_config.ts'; +const jsonInputPath = "../src/schemas/projectConfig.schema.ts"; +const tsOutputPath = "../src/schemas/project_config.ts"; // FIXME Duplicates compilation options in config.test.ts -const compileOptions = { style: { singleQuote: true, trailingComma: 'es5' } }; +const compileOptions = { style: { singleQuote: true, trailingComma: "es5" } }; const schema = require(jsonInputPath); json2ts - .compile(schema, '', compileOptions) - .then(ts => fs.writeFileSync(tsOutputPath, ts)) - .catch(e => console.error(e)); + .compile(schema, "", compileOptions) + .then((ts) => fs.writeFileSync(tsOutputPath, ts)) + .catch((e) => console.error(e)); diff --git a/src/__mocks__/@aws-sdk/client-lambda.ts b/src/__mocks__/@aws-sdk/client-lambda.ts index 64c88b50..8404599a 100644 --- a/src/__mocks__/@aws-sdk/client-lambda.ts +++ b/src/__mocks__/@aws-sdk/client-lambda.ts @@ -2,7 +2,7 @@ const PUBLISHED_LAYER_TEST = { Version: 1, - LayerVersionArn: 'test:layer:version:arn', + LayerVersionArn: "test:layer:version:arn", }; export class Lambda { diff --git a/src/__mocks__/fs.ts b/src/__mocks__/fs.ts index bbadbd3b..e2132777 100644 --- a/src/__mocks__/fs.ts +++ b/src/__mocks__/fs.ts @@ -1,4 +1,4 @@ -const fs: any = jest.createMockFromModule('fs'); +const fs: any = jest.createMockFromModule("fs"); function readFileSync(input: any) { return input; diff --git a/src/__mocks__/logger.ts b/src/__mocks__/logger.ts index 07ace221..2aebf45a 100644 --- a/src/__mocks__/logger.ts +++ b/src/__mocks__/logger.ts @@ -1,9 +1,9 @@ // eslint-disable-next-line @typescript-eslint/no-var-requires -const consola = require('consola'); +const consola = require("consola"); -const loggerModule: typeof consola = jest.genMockFromModule('../logger'); +const loggerModule: typeof consola = jest.genMockFromModule("../logger"); -loggerModule.logger.withScope = function(): any { +loggerModule.logger.withScope = function (): any { return this; }; diff --git a/src/__tests__/config.test.ts b/src/__tests__/config.test.ts index 5adb2f4a..3dcaa4ee 100644 --- a/src/__tests__/config.test.ts +++ b/src/__tests__/config.test.ts @@ -3,48 +3,48 @@ * configuration). */ -import { readFileSync } from 'fs'; -import { dirname, join } from 'path'; +import { readFileSync } from "fs"; +import { dirname, join } from "path"; -import { compile } from 'json-schema-to-typescript'; +import { compile } from "json-schema-to-typescript"; -import { getProjectConfigSchema, validateConfiguration } from '../config'; +import { getProjectConfigSchema, validateConfiguration } from "../config"; -const configSchemaDir = join(dirname(__dirname), 'schemas'); -const configGeneratedTypes = join(configSchemaDir, 'project_config.ts'); +const configSchemaDir = join(dirname(__dirname), "schemas"); +const configGeneratedTypes = join(configSchemaDir, "project_config.ts"); /** * We compile JSON schema to TypeScript interface as part of tests to compare * it with the existing file. This is done to be promptly notified about any * changes to the JSON schema that are not yet reflected in the TS interface. */ -describe('compile-json-schema-to-typescript', () => { - test('does not make any changes to the compiled interface', async () => { +describe("compile-json-schema-to-typescript", () => { + test("does not make any changes to the compiled interface", async () => { // eslint-disable-next-line @typescript-eslint/no-var-requires - const projectConfig = require('../schemas/projectConfig.schema'); + const projectConfig = require("../schemas/projectConfig.schema"); const storedOutput = readFileSync(configGeneratedTypes, { - encoding: 'utf8', + encoding: "utf8", }); const compileOptions = { - style: { singleQuote: true, trailingComma: 'es5' } as any, + style: { singleQuote: true, trailingComma: "es5" } as any, }; - const generatedOutput = await compile(projectConfig, '', compileOptions); + const generatedOutput = await compile(projectConfig, "", compileOptions); expect(generatedOutput).toBeTruthy(); expect(generatedOutput).toBe(storedOutput); }); }); -describe('validateConfiguration', () => { - test('parses minimal configuration', () => { - const data = { github: { owner: 'getsentry', repo: 'craft' } }; +describe("validateConfiguration", () => { + test("parses minimal configuration", () => { + const data = { github: { owner: "getsentry", repo: "craft" } }; const projectConfig = validateConfiguration(data); expect(projectConfig).toEqual(data); }); - test('fails with empty configuration', () => { + test("fails with empty configuration", () => { // this ensures that we do actually run the expect line in the catch block expect.assertions(1); @@ -56,11 +56,11 @@ describe('validateConfiguration', () => { }); }); -describe('getProjectConfigSchema', () => { - test('returns non-empty object', () => { +describe("getProjectConfigSchema", () => { + test("returns non-empty object", () => { const projectConfigSchema = getProjectConfigSchema(); - expect(projectConfigSchema).toHaveProperty('title'); - expect(projectConfigSchema).toHaveProperty('properties'); + expect(projectConfigSchema).toHaveProperty("title"); + expect(projectConfigSchema).toHaveProperty("properties"); }); }); diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts index 642eadb6..3bc8fccf 100644 --- a/src/__tests__/index.test.ts +++ b/src/__tests__/index.test.ts @@ -1,3 +1,3 @@ -test('it works', () => { +test("it works", () => { expect(true).toBeTruthy(); }); diff --git a/src/artifact_providers/base.ts b/src/artifact_providers/base.ts index e90583da..da0b9bd0 100644 --- a/src/artifact_providers/base.ts +++ b/src/artifact_providers/base.ts @@ -2,10 +2,10 @@ import { calculateChecksum, HashAlgorithm, HashOutputFormat, -} from '../utils/system'; -import { clearObjectProperties } from '../utils/objects'; -import { ConfigurationError } from '../utils/errors'; -import { logger as loggerRaw } from '../logger'; +} from "../utils/system"; +import { clearObjectProperties } from "../utils/objects"; +import { ConfigurationError } from "../utils/errors"; +import { logger as loggerRaw } from "../logger"; const logger = loggerRaw.withScope(`[artifact-provider]`); @@ -130,7 +130,7 @@ export abstract class BaseArtifactProvider { if (downloadDirectory) { this.defaultDownloadDirectory = downloadDirectory; } else { - throw new ConfigurationError('Download directory cannot be empty!'); + throw new ConfigurationError("Download directory cannot be empty!"); } } @@ -165,7 +165,7 @@ export abstract class BaseArtifactProvider { } else if (this.defaultDownloadDirectory) { finalDownloadDirectory = this.defaultDownloadDirectory; } else { - throw new Error('Download directory not configured!'); + throw new Error("Download directory not configured!"); } const cacheKey = `${finalDownloadDirectory}/${artifact.filename}/${artifact.storedFile.lastUpdated}`; @@ -179,7 +179,7 @@ export abstract class BaseArtifactProvider { const promise = this.doDownloadArtifact( artifact, finalDownloadDirectory - ).catch(err => { + ).catch((err) => { logger.error( `Unable to download ${artifact.filename} from artifact provider!` ); @@ -221,7 +221,7 @@ export abstract class BaseArtifactProvider { downloadDirectory?: string ): Promise { return Promise.all( - artifacts.map(async artifact => + artifacts.map(async (artifact) => this.downloadArtifact(artifact, downloadDirectory) ) ); @@ -328,13 +328,13 @@ export abstract class BaseArtifactProvider { } const { includeNames, excludeNames } = filterOptions; if (includeNames) { - filteredArtifacts = filteredArtifacts.filter(artifact => + filteredArtifacts = filteredArtifacts.filter((artifact) => includeNames.test(artifact.filename) ); } if (excludeNames) { filteredArtifacts = filteredArtifacts.filter( - artifact => !excludeNames.test(artifact.filename) + (artifact) => !excludeNames.test(artifact.filename) ); } return filteredArtifacts; diff --git a/src/artifact_providers/gcs.ts b/src/artifact_providers/gcs.ts index 07748b39..f6102077 100644 --- a/src/artifact_providers/gcs.ts +++ b/src/artifact_providers/gcs.ts @@ -2,10 +2,10 @@ import { BaseArtifactProvider, RemoteArtifact, ArtifactProviderConfig, -} from '../artifact_providers/base'; -import { CraftGCSClient, getGCSCredsFromEnv } from '../utils/gcsApi'; -import { ConfigurationError } from '../utils/errors'; -import { logger as loggerRaw } from '../logger'; +} from "../artifact_providers/base"; +import { CraftGCSClient, getGCSCredsFromEnv } from "../utils/gcsApi"; +import { ConfigurationError } from "../utils/errors"; +import { logger as loggerRaw } from "../logger"; const logger = loggerRaw.withScope(`[artifact-provider/gcs]`); @@ -28,10 +28,10 @@ export class GCSArtifactProvider extends BaseArtifactProvider { super(config); const { project_id, client_email, private_key } = getGCSCredsFromEnv( { - name: 'CRAFT_GCS_STORE_CREDS_JSON', + name: "CRAFT_GCS_STORE_CREDS_JSON", }, { - name: 'CRAFT_GCS_STORE_CREDS_PATH', + name: "CRAFT_GCS_STORE_CREDS_PATH", }, logger ); @@ -39,7 +39,7 @@ export class GCSArtifactProvider extends BaseArtifactProvider { // TODO (kmclb) get rid of this check once config validation is working if (!config.bucket) { throw new ConfigurationError( - 'No GCS bucket provided in artifact provider config!' + "No GCS bucket provided in artifact provider config!" ); } diff --git a/src/artifact_providers/github.ts b/src/artifact_providers/github.ts index deca0353..e8c971f7 100644 --- a/src/artifact_providers/github.ts +++ b/src/artifact_providers/github.ts @@ -1,24 +1,24 @@ -import Github from '@octokit/rest'; -import * as fs from 'fs'; -import request from 'request'; -import * as path from 'path'; +import Github from "@octokit/rest"; +import * as fs from "fs"; +import request from "request"; +import * as path from "path"; import { ArtifactProviderConfig, BaseArtifactProvider, RemoteArtifact, -} from '../artifact_providers/base'; -import { getGlobalGithubConfig } from '../config'; -import { logger as loggerRaw } from '../logger'; -import { GithubGlobalConfig } from '../schemas/project_config'; -import { getGithubClient } from '../utils/githubApi'; +} from "../artifact_providers/base"; +import { getGlobalGithubConfig } from "../config"; +import { logger as loggerRaw } from "../logger"; +import { GithubGlobalConfig } from "../schemas/project_config"; +import { getGithubClient } from "../utils/githubApi"; import { detectContentType, scan, withTempFile, withTempDir, -} from '../utils/files'; -import { extractZipArchive } from '../utils/system'; +} from "../utils/files"; +import { extractZipArchive } from "../utils/system"; const MAX_TRIES = 3; @@ -91,7 +91,7 @@ export class GithubArtifactProvider extends BaseArtifactProvider { // https://docs.github.com/en/free-pro-team@latest/rest/reference/actions#artifacts const artifactResponse = (( - await this.github.request('GET /repos/{owner}/{repo}/actions/artifacts', { + await this.github.request("GET /repos/{owner}/{repo}/actions/artifacts", { owner: owner, repo: repo, per_page, @@ -103,7 +103,7 @@ export class GithubArtifactProvider extends BaseArtifactProvider { // We need to find the archive where name maches the revision const foundArtifacts = allArtifacts.filter( - artifact => artifact.name === revision + (artifact) => artifact.name === revision ); if (foundArtifacts.length === 1) { @@ -167,26 +167,26 @@ export class GithubArtifactProvider extends BaseArtifactProvider { archiveResponse: ArchiveResponse ): Promise { const artifacts: RemoteArtifact[] = []; - await withTempFile(async tempFilepath => { + await withTempFile(async (tempFilepath) => { const file = fs.createWriteStream(tempFilepath); await new Promise((resolve, reject) => { // we need any here since our github api client doesn't have support for artifacts requests yet request({ uri: archiveResponse.url }) .pipe(file) - .on('finish', () => { + .on("finish", () => { logger.info(`Finished downloading.`); resolve(); }) - .on('error', error => { + .on("error", (error) => { reject(error); }); }); - await withTempDir(async tmpDir => { + await withTempDir(async (tmpDir) => { logger.debug(`Extracting "${tempFilepath}" to "${tmpDir}"...`); await extractZipArchive(tempFilepath, tmpDir); - (await scan(tmpDir)).forEach(file => { + (await scan(tmpDir)).forEach((file) => { artifacts.push({ filename: path.basename(file), mimeType: detectContentType(file), @@ -213,12 +213,12 @@ export class GithubArtifactProvider extends BaseArtifactProvider { const { repoName, repoOwner } = this.config; const archiveResponse = (await this.github.request( - '/repos/{owner}/{repo}/actions/artifacts/{artifact_id}/{archive_format}', + "/repos/{owner}/{repo}/actions/artifacts/{artifact_id}/{archive_format}", { owner: repoOwner, repo: repoName, artifact_id: foundArtifact.id, - archive_format: 'zip', + archive_format: "zip", } )) as ArchiveResponse; diff --git a/src/artifact_providers/none.ts b/src/artifact_providers/none.ts index b997948e..72da8467 100644 --- a/src/artifact_providers/none.ts +++ b/src/artifact_providers/none.ts @@ -2,14 +2,14 @@ import { BaseArtifactProvider, RemoteArtifact, ArtifactProviderConfig, -} from '../artifact_providers/base'; +} from "../artifact_providers/base"; /** * Empty artifact provider that does nothing. */ export class NoneArtifactProvider extends BaseArtifactProvider { public constructor( - config: ArtifactProviderConfig = { repoName: 'none', repoOwner: 'none' } + config: ArtifactProviderConfig = { repoName: "none", repoOwner: "none" } ) { super(config); } @@ -23,7 +23,7 @@ export class NoneArtifactProvider extends BaseArtifactProvider { _downloadDirectory: string ): Promise { return Promise.reject( - new Error('NoneProvider does not suuport file downloads!') + new Error("NoneProvider does not suuport file downloads!") ); } diff --git a/src/artifact_providers/zeus.ts b/src/artifact_providers/zeus.ts index 3222f859..d949fa61 100644 --- a/src/artifact_providers/zeus.ts +++ b/src/artifact_providers/zeus.ts @@ -2,16 +2,16 @@ import { Artifact as ZeusArtifact, Client as ZeusClient, Status, -} from '@zeus-ci/sdk'; -import * as _ from 'lodash'; +} from "@zeus-ci/sdk"; +import * as _ from "lodash"; import { BaseArtifactProvider, RemoteArtifact, ArtifactProviderConfig, -} from '../artifact_providers/base'; -import { checkEnvForPrerequisite } from '../utils/env'; -import { logger as loggerRaw } from '../logger'; +} from "../artifact_providers/base"; +import { checkEnvForPrerequisite } from "../utils/env"; +import { logger as loggerRaw } from "../logger"; const logger = loggerRaw.withScope(`[artifact-provider/zeus]`); @@ -30,8 +30,8 @@ export class ZeusArtifactProvider extends BaseArtifactProvider { public constructor(config: ArtifactProviderConfig) { super(config); checkEnvForPrerequisite({ - legacyName: 'ZEUS_TOKEN', - name: 'ZEUS_API_TOKEN', + legacyName: "ZEUS_TOKEN", + name: "ZEUS_API_TOKEN", }); // We currently need ZEUS_TOKEN set for zeus-sdk to work properly if (!process.env.ZEUS_TOKEN) { @@ -96,10 +96,10 @@ export class ZeusArtifactProvider extends BaseArtifactProvider { name: storedFilename, size, }, - id: '', + id: "", name, status: Status.UNKNOWN, - type: type || '', + type: type || "", updated_at, }; } @@ -143,7 +143,7 @@ export class ZeusArtifactProvider extends BaseArtifactProvider { // return an empty list, whereas in the latter case (unknown commit), it // will error. This error message check and the length check below are // here to disambiguate those two situations. - const errorMessage: string = e.message || ''; + const errorMessage: string = e.message || ""; if (errorMessage.match(/404 not found|resource not found/i)) { logger.debug(`Revision \`${revision}\` not found!`); } @@ -162,22 +162,22 @@ export class ZeusArtifactProvider extends BaseArtifactProvider { // most recent update time const nameToZeusArtifacts = _.groupBy( zeusArtifacts, - zeusArtifact => zeusArtifact.name + (zeusArtifact) => zeusArtifact.name ); const dedupedZeusArtifacts = Object.keys(nameToZeusArtifacts).map( - zeusArtifactName => { + (zeusArtifactName) => { const zeusArtifactObjects = nameToZeusArtifacts[zeusArtifactName]; // Sort by the update time const sortedZeusArtifacts = _.sortBy( zeusArtifactObjects, - zeusArtifactObject => - Date.parse(zeusArtifactObject.updated_at || '') || 0 + (zeusArtifactObject) => + Date.parse(zeusArtifactObject.updated_at || "") || 0 ); return sortedZeusArtifacts[sortedZeusArtifacts.length - 1]; } ); - return dedupedZeusArtifacts.map(zeusArtifact => + return dedupedZeusArtifacts.map((zeusArtifact) => this.convertToRemoteArtifact(zeusArtifact) ); } diff --git a/src/commands/__tests__/prepare.test.ts b/src/commands/__tests__/prepare.test.ts index 58a248e5..47c3847a 100644 --- a/src/commands/__tests__/prepare.test.ts +++ b/src/commands/__tests__/prepare.test.ts @@ -1,36 +1,36 @@ -import { join as pathJoin } from 'path'; -import { spawnProcess } from '../../utils/system'; -import { runPreReleaseCommand } from '../prepare'; +import { join as pathJoin } from "path"; +import { spawnProcess } from "../../utils/system"; +import { runPreReleaseCommand } from "../prepare"; -jest.mock('../../utils/system'); +jest.mock("../../utils/system"); -describe('runPreReleaseCommand', () => { - const newVersion = '2.3.4'; +describe("runPreReleaseCommand", () => { + const newVersion = "2.3.4"; const mockedSpawnProcess = spawnProcess as jest.Mock; beforeEach(() => { jest.clearAllMocks(); }); - test('runs with default command', async () => { + test("runs with default command", async () => { expect.assertions(1); await runPreReleaseCommand(newVersion); expect(mockedSpawnProcess).toBeCalledWith( - '/bin/bash', - [pathJoin('scripts', 'bump-version.sh'), '', newVersion], + "/bin/bash", + [pathJoin("scripts", "bump-version.sh"), "", newVersion], { env: { ...process.env, CRAFT_NEW_VERSION: newVersion, - CRAFT_OLD_VERSION: '', + CRAFT_OLD_VERSION: "", }, } ); }); - test('runs with custom command', async () => { + test("runs with custom command", async () => { expect.assertions(1); await runPreReleaseCommand( @@ -39,13 +39,13 @@ describe('runPreReleaseCommand', () => { ); expect(mockedSpawnProcess).toBeCalledWith( - 'python', - ['./increase_version.py', 'argument 1', '', newVersion], + "python", + ["./increase_version.py", "argument 1", "", newVersion], { env: { ...process.env, CRAFT_NEW_VERSION: newVersion, - CRAFT_OLD_VERSION: '', + CRAFT_OLD_VERSION: "", }, } ); diff --git a/src/commands/__tests__/publish.test.ts b/src/commands/__tests__/publish.test.ts index 6ab58267..ba6408fc 100644 --- a/src/commands/__tests__/publish.test.ts +++ b/src/commands/__tests__/publish.test.ts @@ -1,11 +1,11 @@ -import { join as pathJoin } from 'path'; -import { spawnProcess, hasExecutable } from '../../utils/system'; -import { runPostReleaseCommand } from '../publish'; +import { join as pathJoin } from "path"; +import { spawnProcess, hasExecutable } from "../../utils/system"; +import { runPostReleaseCommand } from "../publish"; -jest.mock('../../utils/system'); +jest.mock("../../utils/system"); -describe('runPostReleaseCommand', () => { - const newVersion = '2.3.4'; +describe("runPostReleaseCommand", () => { + const newVersion = "2.3.4"; const mockedSpawnProcess = spawnProcess as jest.Mock; const mockedHasExecutable = hasExecutable as jest.Mock; @@ -13,27 +13,27 @@ describe('runPostReleaseCommand', () => { jest.clearAllMocks(); }); - describe('default script', () => { - test('runs when script exists', async () => { + describe("default script", () => { + test("runs when script exists", async () => { mockedHasExecutable.mockReturnValue(true); expect.assertions(1); await runPostReleaseCommand(newVersion); expect(mockedSpawnProcess).toBeCalledWith( - '/bin/bash', - [pathJoin('scripts', 'post-release.sh'), '', newVersion], + "/bin/bash", + [pathJoin("scripts", "post-release.sh"), "", newVersion], { env: { ...process.env, CRAFT_NEW_VERSION: newVersion, - CRAFT_OLD_VERSION: '', + CRAFT_OLD_VERSION: "", }, } ); }); - test('skips when script does not exist', async () => { + test("skips when script does not exist", async () => { mockedHasExecutable.mockReturnValue(false); expect.assertions(1); @@ -43,7 +43,7 @@ describe('runPostReleaseCommand', () => { }); }); - test('runs with custom command', async () => { + test("runs with custom command", async () => { expect.assertions(1); await runPostReleaseCommand( @@ -52,13 +52,13 @@ describe('runPostReleaseCommand', () => { ); expect(mockedSpawnProcess).toBeCalledWith( - 'python', - ['./increase_version.py', 'argument 1', '', newVersion], + "python", + ["./increase_version.py", "argument 1", "", newVersion], { env: { ...process.env, CRAFT_NEW_VERSION: newVersion, - CRAFT_OLD_VERSION: '', + CRAFT_OLD_VERSION: "", }, } ); diff --git a/src/commands/artifacts.ts b/src/commands/artifacts.ts index ea4a9c0f..09d0a678 100644 --- a/src/commands/artifacts.ts +++ b/src/commands/artifacts.ts @@ -1,11 +1,11 @@ -import { Argv, CommandBuilder } from 'yargs'; +import { Argv, CommandBuilder } from "yargs"; -import * as download from './artifacts_cmds/download'; -import * as list from './artifacts_cmds/list'; +import * as download from "./artifacts_cmds/download"; +import * as list from "./artifacts_cmds/list"; -export const command = ['artifacts ']; -export const aliases = ['a', 'artifact']; -export const description = '📦 Manage artifacts'; +export const command = ["artifacts "]; +export const aliases = ["a", "artifact"]; +export const description = "📦 Manage artifacts"; /** * Common options for `artifacts` commands @@ -16,13 +16,13 @@ export interface ArtifactsOptions { export const builder: CommandBuilder = (yargs: Argv) => yargs - .option('rev', { - alias: 'r', - description: 'Revision', - type: 'string', + .option("rev", { + alias: "r", + description: "Revision", + type: "string", }) .demandCommand() - .demandOption('rev', 'Please specify the revision') + .demandOption("rev", "Please specify the revision") .command(list) .command(download); diff --git a/src/commands/artifacts_cmds/download.ts b/src/commands/artifacts_cmds/download.ts index 2acdc53d..d45418a2 100644 --- a/src/commands/artifacts_cmds/download.ts +++ b/src/commands/artifacts_cmds/download.ts @@ -1,35 +1,35 @@ -import * as _ from 'lodash'; -import { logger } from '../../logger'; -import { ArtifactsOptions } from '../artifacts'; -import { getArtifactProviderFromConfig } from '../../config'; -import { handleGlobalError, ConfigurationError } from '../../utils/errors'; -import { Argv, CommandBuilder } from 'yargs'; -import { resolve } from 'path'; -import { existsSync, lstatSync } from 'fs'; -import mkdirp = require('mkdirp'); -import { NoneArtifactProvider } from '../../artifact_providers/none'; +import * as _ from "lodash"; +import { logger } from "../../logger"; +import { ArtifactsOptions } from "../artifacts"; +import { getArtifactProviderFromConfig } from "../../config"; +import { handleGlobalError, ConfigurationError } from "../../utils/errors"; +import { Argv, CommandBuilder } from "yargs"; +import { resolve } from "path"; +import { existsSync, lstatSync } from "fs"; +import mkdirp = require("mkdirp"); +import { NoneArtifactProvider } from "../../artifact_providers/none"; -export const command = ['download [NAME..]']; -export const aliases = ['d', 'get']; -export const description = 'Download artifacts'; +export const command = ["download [NAME..]"]; +export const aliases = ["d", "get"]; +export const description = "Download artifacts"; export const builder: CommandBuilder = (yargs: Argv) => yargs - .positional('NAME', { - alias: 'names', - description: 'Artifact name to download', - type: 'string', + .positional("NAME", { + alias: "names", + description: "Artifact name to download", + type: "string", }) - .array('NAME') - .option('all', { - alias: 'a', + .array("NAME") + .option("all", { + alias: "a", default: false, - description: 'Download all artifacts', - type: 'boolean', + description: "Download all artifacts", + type: "boolean", }) - .option('directory', { - alias: 'd', - description: 'Target directory', - type: 'string', + .option("directory", { + alias: "d", + description: "Target directory", + type: "string", }); /** Options for "download" command */ @@ -70,7 +70,7 @@ async function prepareOutputDirectory( */ async function handlerMain(argv: ArtifactsDownloadOptions): Promise { if (!argv.all && argv.names.length === 0) { - throw new ConfigurationError('No names to download, exiting.'); + throw new ConfigurationError("No names to download, exiting."); } const revision = argv.rev; @@ -92,9 +92,9 @@ async function handlerMain(argv: ArtifactsDownloadOptions): Promise { } const filesToDownload = argv.all - ? artifacts.map(ar => ar.filename) + ? artifacts.map((ar) => ar.filename) : argv.names; - const nameToArtifact = _.fromPairs(artifacts.map(ar => [ar.filename, ar])); + const nameToArtifact = _.fromPairs(artifacts.map((ar) => [ar.filename, ar])); logger.info(`Fetching artifacts for revision: ${revision}`); for (const name of filesToDownload) { diff --git a/src/commands/artifacts_cmds/list.ts b/src/commands/artifacts_cmds/list.ts index ab87b6e0..e0300373 100644 --- a/src/commands/artifacts_cmds/list.ts +++ b/src/commands/artifacts_cmds/list.ts @@ -1,13 +1,13 @@ -import { logger, formatTable } from '../../logger'; -import { ArtifactsOptions } from '../artifacts'; -import { getArtifactProviderFromConfig } from '../../config'; -import { handleGlobalError } from '../../utils/errors'; -import { formatSize } from '../../utils/strings'; -import { NoneArtifactProvider } from '../../artifact_providers/none'; +import { logger, formatTable } from "../../logger"; +import { ArtifactsOptions } from "../artifacts"; +import { getArtifactProviderFromConfig } from "../../config"; +import { handleGlobalError } from "../../utils/errors"; +import { formatSize } from "../../utils/strings"; +import { NoneArtifactProvider } from "../../artifact_providers/none"; -export const command = ['list']; -export const aliases = ['l']; -export const description = 'List artifacts'; +export const command = ["list"]; +export const aliases = ["l"]; +export const description = "List artifacts"; /** * Body of 'artifacts list' command @@ -30,16 +30,16 @@ async function handlerMain(argv: ArtifactsOptions): Promise { return undefined; } - const artifactData = artifacts.map(ar => [ + const artifactData = artifacts.map((ar) => [ ar.filename, formatSize(ar.storedFile.size), - ar.storedFile.lastUpdated || '', + ar.storedFile.lastUpdated || "", ]); const table = formatTable( { - head: ['File Name', 'Size', 'Updated'], - style: { head: ['cyan'] }, + head: ["File Name", "Size", "Updated"], + style: { head: ["cyan"] }, }, artifactData ); diff --git a/src/commands/prepare.ts b/src/commands/prepare.ts index ca8c5c3d..9acf8600 100644 --- a/src/commands/prepare.ts +++ b/src/commands/prepare.ts @@ -1,69 +1,69 @@ -import { existsSync, promises as fsPromises } from 'fs'; -import { dirname, join, relative } from 'path'; -import * as shellQuote from 'shell-quote'; -import simpleGit, { SimpleGit } from 'simple-git'; -import { Arguments, Argv, CommandBuilder } from 'yargs'; +import { existsSync, promises as fsPromises } from "fs"; +import { dirname, join, relative } from "path"; +import * as shellQuote from "shell-quote"; +import simpleGit, { SimpleGit } from "simple-git"; +import { Arguments, Argv, CommandBuilder } from "yargs"; import { checkMinimalConfigVersion, getConfigFilePath, getConfiguration, DEFAULT_RELEASE_BRANCH_NAME, -} from '../config'; -import { logger } from '../logger'; -import { ChangelogPolicy } from '../schemas/project_config'; +} from "../config"; +import { logger } from "../logger"; +import { ChangelogPolicy } from "../schemas/project_config"; import { DEFAULT_CHANGELOG_PATH, DEFAULT_UNRELEASED_TITLE, findChangeset, removeChangeset, prependChangeset, -} from '../utils/changes'; +} from "../utils/changes"; import { ConfigurationError, handleGlobalError, reportError, -} from '../utils/errors'; -import { getDefaultBranch, getGithubClient } from '../utils/githubApi'; -import { isDryRun } from '../utils/helpers'; -import { formatJson } from '../utils/strings'; -import { sleepAsync, spawnProcess } from '../utils/system'; -import { isValidVersion, versionToTag } from '../utils/version'; +} from "../utils/errors"; +import { getDefaultBranch, getGithubClient } from "../utils/githubApi"; +import { isDryRun } from "../utils/helpers"; +import { formatJson } from "../utils/strings"; +import { sleepAsync, spawnProcess } from "../utils/system"; +import { isValidVersion, versionToTag } from "../utils/version"; -import { handler as publishMainHandler, PublishOptions } from './publish'; +import { handler as publishMainHandler, PublishOptions } from "./publish"; -export const command = ['prepare NEW-VERSION']; -export const aliases = ['p', 'prerelease', 'prepublish', 'prepare', 'release']; -export const description = '🚢 Prepare a new release branch'; +export const command = ["prepare NEW-VERSION"]; +export const aliases = ["p", "prerelease", "prepublish", "prepare", "release"]; +export const description = "🚢 Prepare a new release branch"; /** Default path to bump-version script, relative to project root */ -const DEFAULT_BUMP_VERSION_PATH = join('scripts', 'bump-version.sh'); +const DEFAULT_BUMP_VERSION_PATH = join("scripts", "bump-version.sh"); export const builder: CommandBuilder = (yargs: Argv) => yargs - .positional('NEW-VERSION', { - description: 'The new version you want to release', - type: 'string', + .positional("NEW-VERSION", { + description: "The new version you want to release", + type: "string", }) - .option('no-push', { + .option("no-push", { default: false, - description: 'Do not push the release branch', - type: 'boolean', + description: "Do not push the release branch", + type: "boolean", }) - .option('no-git-checks', { + .option("no-git-checks", { default: false, - description: 'Ignore local git changes and unsynchronized remotes', - type: 'boolean', + description: "Ignore local git changes and unsynchronized remotes", + type: "boolean", }) - .option('no-changelog', { + .option("no-changelog", { default: false, - description: 'Do not check for changelog entries', - type: 'boolean', + description: "Do not check for changelog entries", + type: "boolean", }) - .option('publish', { + .option("publish", { default: false, description: 'Run "publish" right after "release"', - type: 'boolean', + type: "boolean", }) .check(checkVersionOrPart); @@ -98,8 +98,8 @@ const SLEEP_BEFORE_PUBLISH_SECONDS = 30; */ function checkVersionOrPart(argv: Arguments, _opt: any): any { const version = argv.newVersion; - if (['major', 'minor', 'patch'].indexOf(version) > -1) { - throw Error('Version part is not supported yet'); + if (["major", "minor", "patch"].indexOf(version) > -1) { + throw Error("Version part is not supported yet"); } else if (isValidVersion(version)) { return true; } else { @@ -124,7 +124,7 @@ async function createReleaseBranch( const branchPrefix = releaseBranchPrefix || DEFAULT_RELEASE_BRANCH_NAME; const branchName = `${branchPrefix}/${newVersion}`; - const branchHead = await git.raw(['show-ref', '--heads', branchName]); + const branchHead = await git.raw(["show-ref", "--heads", branchName]); // in case `show-ref` can't find a branch it returns `null` if (branchHead) { @@ -141,7 +141,7 @@ async function createReleaseBranch( logger.info(`Created a new release branch: "${branchName}"`); logger.info(`Switched to branch "${branchName}"`); } else { - logger.info('[dry-run] Not creating a new release branch'); + logger.info("[dry-run] Not creating a new release branch"); } return branchName; } @@ -163,14 +163,14 @@ async function pushReleaseBranch( logger.info(`Pushing the release branch "${branchName}"...`); // TODO check remote somehow if (!isDryRun()) { - await git.push(remoteName, branchName, ['--set-upstream']); + await git.push(remoteName, branchName, ["--set-upstream"]); } else { - logger.info('[dry-run] Not pushing the release branch.'); + logger.info("[dry-run] Not pushing the release branch."); } } else { - logger.info('Not pushing the release branch.'); + logger.info("Not pushing the release branch."); logger.info( - 'You can push this branch later using the following command:', + "You can push this branch later using the following command:", ` $ git push -u ${remoteName} "${branchName}"` ); } @@ -189,15 +189,15 @@ async function commitNewVersion( const message = `release: ${newVersion}`; const repoStatus = await git.status(); if (!(repoStatus.created.length || repoStatus.modified.length)) { - reportError('Nothing to commit: has the pre-release command done its job?'); + reportError("Nothing to commit: has the pre-release command done its job?"); } - logger.info('Committing the release changes...'); + logger.info("Committing the release changes..."); logger.debug(`Commit message: "${message}"`); if (!isDryRun()) { - await git.commit(message, ['--all']); + await git.commit(message, ["--all"]); } else { - logger.info('[dry-run] Not committing the changes.'); + logger.info("[dry-run] Not committing the changes."); } } @@ -218,19 +218,19 @@ export async function runPreReleaseCommand( let args: string[]; if (preReleaseCommand !== undefined && preReleaseCommand.length === 0) { // Not running pre-release command - logger.warn('Not running the pre-release command: no command specified'); + logger.warn("Not running the pre-release command: no command specified"); return false; } else if (preReleaseCommand) { [sysCommand, ...args] = shellQuote.parse(preReleaseCommand) as string[]; } else { - sysCommand = '/bin/bash'; + sysCommand = "/bin/bash"; args = [DEFAULT_BUMP_VERSION_PATH]; } - args = [...args, '', newVersion]; + args = [...args, "", newVersion]; logger.info(`Running the pre-release command...`); const additionalEnv = { CRAFT_NEW_VERSION: newVersion, - CRAFT_OLD_VERSION: '', + CRAFT_OLD_VERSION: "", }; await spawnProcess(sysCommand, args, { env: { ...process.env, ...additionalEnv }, @@ -251,17 +251,17 @@ async function checkGitState( checkGitStatus = true ): Promise { if (!checkGitStatus) { - logger.warn('Not checking the status of the local repository'); + logger.warn("Not checking the status of the local repository"); return; } - logger.info('Checking the local repository status...'); + logger.info("Checking the local repository status..."); const isRepo = await git.checkIsRepo(); if (!isRepo) { - throw new ConfigurationError('Not a git repository!'); + throw new ConfigurationError("Not a git repository!"); } const repoStatus = await git.status(); - logger.debug('Repository status:', formatJson(repoStatus)); + logger.debug("Repository status:", formatJson(repoStatus)); // Check that we are on master // TODO check what's here when we are in a detached state @@ -280,8 +280,8 @@ async function checkGitState( repoStatus.staged.length ) { reportError( - 'Your repository is in a dirty state. ' + - 'Please stash or commit the pending changes.', + "Your repository is in a dirty state. " + + "Please stash or commit the pending changes.", logger ); } @@ -317,7 +317,7 @@ async function execPublish(newVersion: string): Promise { if (!isDryRun()) { await sleepAsync(SLEEP_BEFORE_PUBLISH_SECONDS * 1000); } else { - logger.info('[dry-run] Not wasting time on sleep'); + logger.info("[dry-run] Not wasting time on sleep"); } try { @@ -331,7 +331,7 @@ async function execPublish(newVersion: string): Promise { ); throw e; } - throw new Error('Unreachable'); + throw new Error("Unreachable"); } /** @@ -347,7 +347,7 @@ async function checkForExistingTag( checkGitStatus = true ): Promise { if (!checkGitStatus) { - logger.warn('Not checking if the version (git tag) already exists'); + logger.warn("Not checking if the version (git tag) already exists"); } const gitTag = versionToTag(newVersion); @@ -384,11 +384,11 @@ async function prepareChangelog( ); } - logger.info('Checking the changelog...'); + logger.info("Checking the changelog..."); logger.debug(`Changelog policy: "${changelogPolicy}".`); - const relativePath = relative('', changelogPath); - if (relativePath.startsWith('.')) { + const relativePath = relative("", changelogPath); + if (relativePath.startsWith(".")) { throw new ConfigurationError(`Invalid changelog path: "${changelogPath}"`); } @@ -411,7 +411,7 @@ async function prepareChangelog( // eslint-disable-next-line no-case-declarations let replaceSection; if (!changeset) { - changeset = { name: newVersion, body: '' }; + changeset = { name: newVersion, body: "" }; } if (!changeset.body) { replaceSection = changeset.name; @@ -432,7 +432,7 @@ async function prepareChangelog( if (!isDryRun()) { await fsPromises.writeFile(relativePath, changelogString); } else { - logger.info('[dry-run] Not updating changelog file.'); + logger.info("[dry-run] Not updating changelog file."); logger.debug(`New changelog:\n${changelogString}`); } @@ -466,7 +466,7 @@ async function switchToDefaultBranch( if (!isDryRun()) { await git.checkout(defaultBranch); } else { - logger.info('[dry-run] Not switching branches.'); + logger.info("[dry-run] Not switching branches."); } } @@ -476,7 +476,7 @@ async function switchToDefaultBranch( * @param argv Command-line arguments */ export async function releaseMain(argv: ReleaseOptions): Promise { - logger.debug('Argv: ', JSON.stringify(argv)); + logger.debug("Argv: ", JSON.stringify(argv)); checkMinimalConfigVersion(); // Get repo configuration @@ -534,7 +534,7 @@ export async function releaseMain(argv: ReleaseOptions): Promise { // Commit the pending changes await commitNewVersion(git, newVersion); } else { - logger.debug('Not committing anything since preReleaseCommand is empty.'); + logger.debug("Not committing anything since preReleaseCommand is empty."); } // Push the release branch @@ -563,7 +563,7 @@ export async function releaseMain(argv: ReleaseOptions): Promise { * @returns Git remote name from environment or default */ function getRemoteName(): string { - return process.env.CRAFT_REMOTE || 'origin'; + return process.env.CRAFT_REMOTE || "origin"; } export const handler = async (args: { diff --git a/src/commands/publish.ts b/src/commands/publish.ts index 53008211..1e79b134 100644 --- a/src/commands/publish.ts +++ b/src/commands/publish.ts @@ -1,16 +1,16 @@ -import * as Github from '@octokit/rest'; -import * as inquirer from 'inquirer'; -import { Arguments, Argv, CommandBuilder } from 'yargs'; -import chalk from 'chalk'; +import * as Github from "@octokit/rest"; +import * as inquirer from "inquirer"; +import { Arguments, Argv, CommandBuilder } from "yargs"; +import chalk from "chalk"; import { existsSync, readFileSync, writeFileSync, promises as fsPromises, -} from 'fs'; -import { join } from 'path'; -import shellQuote from 'shell-quote'; -import stringLength from 'string-length'; +} from "fs"; +import { join } from "path"; +import shellQuote from "shell-quote"; +import stringLength from "string-length"; import { checkMinimalConfigVersion, @@ -18,89 +18,89 @@ import { getStatusProviderFromConfig, getArtifactProviderFromConfig, DEFAULT_RELEASE_BRANCH_NAME, -} from '../config'; -import { formatTable, logger } from '../logger'; -import { GithubGlobalConfig, TargetConfig } from '../schemas/project_config'; +} from "../config"; +import { formatTable, logger } from "../logger"; +import { GithubGlobalConfig, TargetConfig } from "../schemas/project_config"; import { getAllTargetNames, getTargetByName, getTargetId, SpecialTarget, -} from '../targets'; -import { BaseTarget } from '../targets/base'; -import { coerceType, handleGlobalError, reportError } from '../utils/errors'; -import { withTempDir } from '../utils/files'; -import { stringToRegexp } from '../utils/filters'; -import { getGithubClient, mergeReleaseBranch } from '../utils/githubApi'; -import { isDryRun } from '../utils/helpers'; -import { hasInput } from '../utils/noInput'; -import { formatSize, formatJson } from '../utils/strings'; +} from "../targets"; +import { BaseTarget } from "../targets/base"; +import { coerceType, handleGlobalError, reportError } from "../utils/errors"; +import { withTempDir } from "../utils/files"; +import { stringToRegexp } from "../utils/filters"; +import { getGithubClient, mergeReleaseBranch } from "../utils/githubApi"; +import { isDryRun } from "../utils/helpers"; +import { hasInput } from "../utils/noInput"; +import { formatSize, formatJson } from "../utils/strings"; import { catchKeyboardInterrupt, hasExecutable, spawnProcess, -} from '../utils/system'; -import { isValidVersion } from '../utils/version'; -import { BaseStatusProvider } from '../status_providers/base'; -import { BaseArtifactProvider } from '../artifact_providers/base'; +} from "../utils/system"; +import { isValidVersion } from "../utils/version"; +import { BaseStatusProvider } from "../status_providers/base"; +import { BaseArtifactProvider } from "../artifact_providers/base"; /** Default path to post-release script, relative to project root */ -const DEFAULT_POST_RELEASE_SCRIPT_PATH = join('scripts', 'post-release.sh'); +const DEFAULT_POST_RELEASE_SCRIPT_PATH = join("scripts", "post-release.sh"); -export const command = ['publish NEW-VERSION']; -export const aliases = ['pp', 'publish']; -export const description = '🛫 Publish artifacts'; +export const command = ["publish NEW-VERSION"]; +export const aliases = ["pp", "publish"]; +export const description = "🛫 Publish artifacts"; export const builder: CommandBuilder = (yargs: Argv) => { const definedTargets = getConfiguration().targets || []; const possibleTargetNames = new Set(getAllTargetNames()); const allowedTargetNames = definedTargets - .filter(target => target.name && possibleTargetNames.has(target.name)) + .filter((target) => target.name && possibleTargetNames.has(target.name)) .map(getTargetId); return yargs - .positional('NEW-VERSION', { - description: 'Version to publish', - type: 'string', + .positional("NEW-VERSION", { + description: "Version to publish", + type: "string", }) - .option('target', { - alias: 't', + .option("target", { + alias: "t", choices: allowedTargetNames.concat([ SpecialTarget.All, SpecialTarget.None, ]), default: SpecialTarget.All, - description: 'Publish to this target', - type: 'string', + description: "Publish to this target", + type: "string", }) - .option('rev', { - alias: 'r', + .option("rev", { + alias: "r", description: - 'Source revision (git SHA or tag) to publish (if not release branch head)', - type: 'string', + "Source revision (git SHA or tag) to publish (if not release branch head)", + type: "string", }) - .option('no-merge', { + .option("no-merge", { default: false, - description: 'Do not merge the release branch after publishing', - type: 'boolean', + description: "Do not merge the release branch after publishing", + type: "boolean", }) - .option('keep-branch', { + .option("keep-branch", { default: false, - description: 'Do not remove release branch after merging it', - type: 'boolean', + description: "Do not remove release branch after merging it", + type: "boolean", }) - .option('keep-downloads', { + .option("keep-downloads", { default: false, - description: 'Keep all downloaded files', - type: 'boolean', + description: "Keep all downloaded files", + type: "boolean", }) - .option('no-status-check', { + .option("no-status-check", { default: false, - description: 'Do not check for build status', - type: 'boolean', + description: "Do not check for build status", + type: "boolean", }) .check(checkVersion) - .demandOption('new-version', 'Please specify the version to publish'); + .demandOption("new-version", "Please specify the version to publish"); }; /** Command line options. */ @@ -157,8 +157,8 @@ async function publishToTarget( const publishMessage = `=== Publishing to target: ${chalk.bold( chalk.cyan(getTargetId(target.config)) )} ===`; - const delim = Array(stringLength(publishMessage) + 1).join('='); - logger.info(' '); + const delim = Array(stringLength(publishMessage) + 1).join("="); + logger.info(" "); logger.info(delim); logger.info(publishMessage); logger.info(delim); @@ -177,29 +177,29 @@ async function printRevisionSummary( ): Promise { const artifacts = await artifactProvider.listArtifactsForRevision(revision); if (artifacts.length > 0) { - const artifactData = artifacts.map(ar => [ + const artifactData = artifacts.map((ar) => [ ar.filename, formatSize(ar.storedFile.size), - ar.storedFile.lastUpdated || '', + ar.storedFile.lastUpdated || "", // sometimes mimeTypes are stored with the encoding included, e.g. // `application/javascript; charset=utf-8`, but we only really care about // the first part - (ar.mimeType && ar.mimeType.split(';')[0]) || '', + (ar.mimeType && ar.mimeType.split(";")[0]) || "", ]); // sort alphabetically by filename artifactData.sort((a1, a2) => (a1[0] < a2[0] ? -1 : a1[0] > a2[0] ? 1 : 0)); const table = formatTable( { - head: ['File Name', 'Size', 'Updated', 'ContentType'], - style: { head: ['cyan'] }, + head: ["File Name", "Size", "Updated", "ContentType"], + style: { head: ["cyan"] }, }, artifactData ); - logger.info(' '); + logger.info(" "); logger.info(`Available artifacts: \n${table.toString()}\n`); } else { - logger.warn('No artifacts found for the revision.'); + logger.warn("No artifacts found for the revision."); } } @@ -207,19 +207,19 @@ async function printRevisionSummary( * Prompt the user that everything is OK and we should proceed with publishing */ async function promptConfirmation(targetList: BaseTarget[]): Promise { - logger.info('Publishing to targets:'); + logger.info("Publishing to targets:"); logger.info( - targetList.map(target => ` - ${getTargetId(target.config)}`).join('\n') + targetList.map((target) => ` - ${getTargetId(target.config)}`).join("\n") ); - logger.info(' '); + logger.info(" "); if (hasInput()) { const questions = [ { message: 'Is everything OK? Type "yes" to proceed:', - name: 'readyToPublish', - type: 'input', + name: "readyToPublish", + type: "input", // Force the user to type something that is not empty or one letter such // as y/n to make sure this is a concious choice. validate: (input: string) => @@ -227,13 +227,13 @@ async function promptConfirmation(targetList: BaseTarget[]): Promise { }, ]; const answers = (await inquirer.prompt(questions)) as any; - const readyToPublish = coerceType(answers.readyToPublish, 'string'); - if (readyToPublish.toLowerCase() !== 'yes') { - logger.error('Oh, okay. Aborting.'); + const readyToPublish = coerceType(answers.readyToPublish, "string"); + if (readyToPublish.toLowerCase() !== "yes") { + logger.error("Oh, okay. Aborting."); process.exit(1); } } else { - logger.debug('Skipping the prompting.'); + logger.debug("Skipping the prompting."); } } @@ -241,7 +241,7 @@ async function getTargetList( targetConfigList: TargetConfig[], artifactProvider: BaseArtifactProvider ): Promise { - logger.debug('Initializing targets'); + logger.debug("Initializing targets"); const targetList: BaseTarget[] = []; for (const targetConfig of targetConfigList) { const targetClass = getTargetByName(targetConfig.name); @@ -283,7 +283,7 @@ async function checkRequiredArtifacts( if (!requiredNames || requiredNames.length === 0) { return; } - logger.debug('Checking that the required artifact names are present...'); + logger.debug("Checking that the required artifact names are present..."); const artifacts = await artifactProvider.listArtifactsForRevision(revision); // innocent until proven guilty... @@ -291,7 +291,7 @@ async function checkRequiredArtifacts( for (const requiredNameRegexString of requiredNames) { const requiredNameRegex = stringToRegexp(requiredNameRegexString); - const matchedArtifacts = artifacts.filter(artifact => + const matchedArtifacts = artifacts.filter((artifact) => requiredNameRegex.test(artifact.filename) ); if (matchedArtifacts.length === 0) { @@ -334,13 +334,13 @@ async function checkRevisionStatus( } try { - logger.debug('Fetching repository information...'); + logger.debug("Fetching repository information..."); // This will additionally check that the user has proper permissions const repositoryInfo = await statusProvider.getRepositoryInfo(); logger.debug(`Repository info received: "${formatJson(repositoryInfo)}"`); } catch (e) { reportError( - 'Cannot get repository information from Zeus. Check your configuration and credentials. ' + + "Cannot get repository information from Zeus. Check your configuration and credentials. " + `Error: ${e.message}` ); } @@ -368,7 +368,7 @@ async function handleReleaseBranch( keepBranch = false ): Promise { if (!branchName || skipMerge) { - logger.info('Skipping the merge step.'); + logger.info("Skipping the merge step."); return; } @@ -381,11 +381,11 @@ async function handleReleaseBranch( branchName ); } else { - logger.info('[dry-run] Not merging the release branch'); + logger.info("[dry-run] Not merging the release branch"); } if (keepBranch) { - logger.info('Not deleting the release branch.'); + logger.info("Not deleting the release branch."); } else { const ref = `heads/${branchName}`; logger.debug(`Deleting the release branch, ref: ${ref}`); @@ -401,7 +401,7 @@ async function handleReleaseBranch( ); logger.info(`Removed the remote branch: "${branchName}"`); } else { - logger.info('[dry-run] Not deleting the remote branch'); + logger.info("[dry-run] Not deleting the remote branch"); } } } @@ -423,12 +423,12 @@ export async function runPostReleaseCommand( let args: shellQuote.ParseEntry[]; if (postReleaseCommand !== undefined && postReleaseCommand.length === 0) { // Not running post-release command - logger.debug('Not running the post-release command: no command specified'); + logger.debug("Not running the post-release command: no command specified"); return false; } else if (postReleaseCommand) { [sysCommand, ...args] = shellQuote.parse(postReleaseCommand); } else if (hasExecutable(DEFAULT_POST_RELEASE_SCRIPT_PATH)) { - sysCommand = '/bin/bash'; + sysCommand = "/bin/bash"; args = [DEFAULT_POST_RELEASE_SCRIPT_PATH]; } else { // Not running post-release command @@ -437,11 +437,11 @@ export async function runPostReleaseCommand( ); return false; } - args = [...args, '', newVersion]; + args = [...args, "", newVersion]; logger.info(`Running the post-release command...`); const additionalEnv = { CRAFT_NEW_VERSION: newVersion, - CRAFT_OLD_VERSION: '', + CRAFT_OLD_VERSION: "", }; await spawnProcess(sysCommand as string, args as string[], { env: { ...process.env, ...additionalEnv }, @@ -455,7 +455,7 @@ export async function runPostReleaseCommand( * @param argv Command-line arguments */ export async function publishMain(argv: PublishOptions): Promise { - logger.debug('Argv:', JSON.stringify(argv)); + logger.debug("Argv:", JSON.stringify(argv)); checkMinimalConfigVersion(); // Get publishing configuration @@ -470,7 +470,7 @@ export async function publishMain(argv: PublishOptions): Promise { let revision: string; let branchName; if (argv.rev) { - branchName = ''; + branchName = ""; logger.debug( `Fetching GitHub information for provided revision: "${argv.rev}"` ); @@ -486,7 +486,7 @@ export async function publishMain(argv: PublishOptions): Promise { config.releaseBranchPrefix || DEFAULT_RELEASE_BRANCH_NAME; branchName = `${branchPrefix}/${newVersion}`; - logger.debug('Fetching branch information', branchName); + logger.debug("Fetching branch information", branchName); const response = await githubClient.repos.getBranch({ branch: branchName, owner: githubConfig.owner, @@ -494,7 +494,7 @@ export async function publishMain(argv: PublishOptions): Promise { }); revision = response.data.commit.sha; } - logger.debug('Revision to publish: ', revision); + logger.debug("Revision to publish: ", revision); const statusProvider = getStatusProviderFromConfig(); const artifactProvider = getArtifactProviderFromConfig(); @@ -509,7 +509,7 @@ export async function publishMain(argv: PublishOptions): Promise { // Find targets let targetsToPublish: Set = new Set( - (typeof argv.target === 'string' ? [argv.target] : argv.target) || [ + (typeof argv.target === "string" ? [argv.target] : argv.target) || [ SpecialTarget.All, ] ); @@ -546,13 +546,17 @@ export async function publishMain(argv: PublishOptions): Promise { } if (!targetsToPublish.has(SpecialTarget.All)) { - targetConfigList = targetConfigList.filter(targetConf => + targetConfigList = targetConfigList.filter((targetConf) => targetsToPublish.has(getTargetId(targetConf)) ); } - if (!targetsToPublish.has(SpecialTarget.None) && !earlierStateExists && targetConfigList.length === 0) { - logger.warn('No valid targets detected! Exiting.'); + if ( + !targetsToPublish.has(SpecialTarget.None) && + !earlierStateExists && + targetConfigList.length === 0 + ) { + logger.warn("No valid targets detected! Exiting."); return undefined; } @@ -574,17 +578,17 @@ export async function publishMain(argv: PublishOptions): Promise { if (argv.keepDownloads) { logger.info( - 'Directory with the downloaded artifacts will not be removed', + "Directory with the downloaded artifacts will not be removed", `Path: ${downloadDirectory}` ); } }, !argv.keepDownloads); - logger.info(' '); + logger.info(" "); } if (argv.rev) { - logger.info('Not merging any branches because revision was specified.'); + logger.info("Not merging any branches because revision was specified."); } else if ( targetsToPublish.has(SpecialTarget.All) || targetsToPublish.has(SpecialTarget.None) || @@ -610,11 +614,11 @@ export async function publishMain(argv: PublishOptions): Promise { logger.success(`Version ${newVersion} has been published!`); } else { const msg = [ - 'The release branch was not merged because you published only to specific targets.', - 'After all the targets are published, run the following command to merge the release branch:', + "The release branch was not merged because you published only to specific targets.", + "After all the targets are published, run the following command to merge the release branch:", ` $ craft publish ${newVersion} --target none\n`, ]; - logger.warn(msg.join('\n')); + logger.warn(msg.join("\n")); } // Run the post-release script diff --git a/src/commands/targets.ts b/src/commands/targets.ts index 043707ce..1023623d 100644 --- a/src/commands/targets.ts +++ b/src/commands/targets.ts @@ -1,15 +1,15 @@ -import { getConfiguration } from '../config'; -import { formatJson } from '../utils/strings'; -import { getAllTargetNames, getTargetId } from '../targets'; +import { getConfiguration } from "../config"; +import { formatJson } from "../utils/strings"; +import { getAllTargetNames, getTargetId } from "../targets"; -export const command = ['targets']; -export const description = 'List defined targets as JSON array'; +export const command = ["targets"]; +export const description = "List defined targets as JSON array"; export function handler(): any { const definedTargets = getConfiguration().targets || []; const possibleTargetNames = new Set(getAllTargetNames()); const allowedTargetNames = definedTargets - .filter(target => target.name && possibleTargetNames.has(target.name)) + .filter((target) => target.name && possibleTargetNames.has(target.name)) .map(getTargetId); console.log(formatJson(allowedTargetNames)); diff --git a/src/config.ts b/src/config.ts index 12be9f40..0af2f5f9 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,44 +1,44 @@ -import { existsSync, lstatSync, readFileSync } from 'fs'; -import { dirname, join } from 'path'; +import { existsSync, lstatSync, readFileSync } from "fs"; +import { dirname, join } from "path"; -import ajv from 'ajv'; -import { safeLoad } from 'js-yaml'; +import ajv from "ajv"; +import { safeLoad } from "js-yaml"; -import { logger } from './logger'; +import { logger } from "./logger"; import { CraftProjectConfig, GithubGlobalConfig, ArtifactProviderName, StatusProviderName, -} from './schemas/project_config'; -import { ConfigurationError } from './utils/errors'; +} from "./schemas/project_config"; +import { ConfigurationError } from "./utils/errors"; import { getPackageVersion, parseVersion, versionGreaterOrEqualThan, -} from './utils/version'; -import { BaseArtifactProvider } from './artifact_providers/base'; -import { GithubArtifactProvider } from './artifact_providers/github'; -import { ZeusArtifactProvider } from './artifact_providers/zeus'; -import { NoneArtifactProvider } from './artifact_providers/none'; -import { GCSArtifactProvider } from './artifact_providers/gcs'; +} from "./utils/version"; +import { BaseArtifactProvider } from "./artifact_providers/base"; +import { GithubArtifactProvider } from "./artifact_providers/github"; +import { ZeusArtifactProvider } from "./artifact_providers/zeus"; +import { NoneArtifactProvider } from "./artifact_providers/none"; +import { GCSArtifactProvider } from "./artifact_providers/gcs"; -import { ZeusStatusProvider } from './status_providers/zeus'; -import { GithubStatusProvider } from './status_providers/github'; -import { BaseStatusProvider } from './status_providers/base'; +import { ZeusStatusProvider } from "./status_providers/zeus"; +import { GithubStatusProvider } from "./status_providers/github"; +import { BaseStatusProvider } from "./status_providers/base"; // TODO support multiple configuration files (one per configuration) -export const CONFIG_FILE_NAME = '.craft.yml'; +export const CONFIG_FILE_NAME = ".craft.yml"; /** * The default prefix for the release branch. */ -export const DEFAULT_RELEASE_BRANCH_NAME = 'release'; +export const DEFAULT_RELEASE_BRANCH_NAME = "release"; /** * Epoch version for changing all defaults to GitHub */ -export const DEFAULTS_EPOCH_VERSION = '0.21.0'; +export const DEFAULTS_EPOCH_VERSION = "0.21.0"; /** * Cached path to the configuration file @@ -78,7 +78,7 @@ export function findConfigFile(): string | undefined { currentDir = parentDir; depth += 1; } - logger.warn('findConfigFile: Reached maximum allowed directory depth'); + logger.warn("findConfigFile: Reached maximum allowed directory depth"); return undefined; } @@ -114,7 +114,7 @@ export function getConfigFileDir(): string | undefined { * Reads JSON schema for project configuration */ export function getProjectConfigSchema(): any { - return require('./schemas/projectConfig.schema'); + return require("./schemas/projectConfig.schema"); } /** @@ -127,8 +127,8 @@ export function getProjectConfigSchema(): any { export function validateConfiguration( rawConfig: Record ): CraftProjectConfig { - logger.debug('Parsing and validating the configuration file...'); - const schemaName = 'projectConfig'; + logger.debug("Parsing and validating the configuration file..."); + const schemaName = "projectConfig"; const projectConfigSchema = getProjectConfigSchema(); const ajvValidator = new ajv().addSchema(projectConfigSchema, schemaName); const valid = ajvValidator.validate(schemaName, rawConfig); @@ -150,8 +150,8 @@ export function getConfiguration(): CraftProjectConfig { } const configPath = getConfigFilePath(); - logger.debug('Configuration file found: ', configPath); - const rawConfig = safeLoad(readFileSync(configPath, 'utf-8')) as Record< + logger.debug("Configuration file found: ", configPath); + const rawConfig = safeLoad(readFileSync(configPath, "utf-8")) as Record< string, any >; @@ -170,14 +170,14 @@ export function checkMinimalConfigVersion(): void { const minVersionRaw = config.minVersion; if (!minVersionRaw) { logger.debug( - 'No minimal version specified in the configuration, skpipping the check' + "No minimal version specified in the configuration, skpipping the check" ); return; } const currentVersionRaw = getPackageVersion(); if (!currentVersionRaw) { - throw new Error('Cannot get the current craft version'); + throw new Error("Cannot get the current craft version"); } const minVersion = parseVersion(minVersionRaw); @@ -232,16 +232,16 @@ export function getGlobalGithubConfig(): GithubGlobalConfig { if (!repoGithubConfig) { throw new ConfigurationError( - 'GitHub configuration not found in the config file' + "GitHub configuration not found in the config file" ); } if (!repoGithubConfig.owner) { - throw new ConfigurationError('GitHub target: owner not found'); + throw new ConfigurationError("GitHub target: owner not found"); } if (!repoGithubConfig.repo) { - throw new ConfigurationError('GitHub target: repo not found'); + throw new ConfigurationError("GitHub target: repo not found"); } return repoGithubConfig; @@ -252,8 +252,8 @@ export function getGlobalGithubConfig(): GithubGlobalConfig { */ export function getGitTagPrefix(): string { const targets = getConfiguration().targets || []; - const githubTarget = targets.find(target => target.name === 'github'); - return githubTarget?.tagPrefix || ''; + const githubTarget = targets.find((target) => target.name === "github"); + return githubTarget?.tagPrefix || ""; } /** @@ -296,7 +296,7 @@ export function getArtifactProviderFromConfig(): BaseArtifactProvider { case ArtifactProviderName.Github: return new GithubArtifactProvider(artifactProviderConfig); default: { - throw new ConfigurationError('Invalid artifact provider'); + throw new ConfigurationError("Invalid artifact provider"); } } } @@ -345,7 +345,7 @@ export function getStatusProviderFromConfig(): BaseStatusProvider { statusProviderConfig ); default: { - throw new ConfigurationError('Invalid status provider'); + throw new ConfigurationError("Invalid status provider"); } } } diff --git a/src/index.ts b/src/index.ts index 42efd21c..99d7b1cf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,19 +1,19 @@ #!/usr/bin/env node -import once from 'once'; -import yargs from 'yargs'; +import once from "once"; +import yargs from "yargs"; -import { logger, init as initLogger } from './logger'; -import { readEnvironmentConfig } from './utils/env'; -import { isDryRun } from './utils/helpers'; -import { hasNoInput, setNoInput } from './utils/noInput'; -import { initSentrySdk } from './utils/sentry'; -import { getPackageVersion } from './utils/version'; +import { logger, init as initLogger } from "./logger"; +import { readEnvironmentConfig } from "./utils/env"; +import { isDryRun } from "./utils/helpers"; +import { hasNoInput, setNoInput } from "./utils/noInput"; +import { initSentrySdk } from "./utils/sentry"; +import { getPackageVersion } from "./utils/version"; // Commands -import * as prepare from './commands/prepare'; -import * as publish from './commands/publish'; -import * as targets from './commands/targets'; -import * as artifacts from './commands/artifacts'; +import * as prepare from "./commands/prepare"; +import * as publish from "./commands/publish"; +import * as targets from "./commands/targets"; +import * as artifacts from "./commands/artifacts"; /** * Handler for '--dry-run' option @@ -21,12 +21,12 @@ import * as artifacts from './commands/artifacts'; function processDryRun(arg: T): T { // if the user explicitly set the flag on the command line, their choice // should override any previously set env var - if (process.argv.indexOf('--dry-run') > -1) { + if (process.argv.indexOf("--dry-run") > -1) { process.env.DRY_RUN = String(arg); } if (isDryRun()) { - logger.info('[dry-run] Dry-run mode is on!'); + logger.info("[dry-run] Dry-run mode is on!"); } return arg; @@ -40,7 +40,7 @@ function processNoInput(arg: T): T { setNoInput(true); } if (hasNoInput()) { - logger.debug('[no-input] The script will not accept any input!'); + logger.debug("[no-input] The script will not accept any input!"); } return arg; } @@ -49,7 +49,7 @@ function processNoInput(arg: T): T { * Prints the current version */ function printVersion(): void { - if (!process.argv.includes('-v') && !process.argv.includes('--version')) { + if (!process.argv.includes("-v") && !process.argv.includes("--version")) { // Print the current version logger.debug(`craft ${getPackageVersion()}`); } @@ -69,7 +69,7 @@ function main(): void { yargs .parserConfiguration({ - 'boolean-negation': false, + "boolean-negation": false, }) .command(prepare) .command(publish) @@ -77,23 +77,23 @@ function main(): void { .command(artifacts) .demandCommand() .version() - .alias('v', 'version') + .alias("v", "version") .help() - .alias('h', 'help') - .option('no-input', { + .alias("h", "help") + .option("no-input", { boolean: true, coerce: once(processNoInput), default: false, - describe: 'Suppresses all user prompts', + describe: "Suppresses all user prompts", }) - .global('no-input') - .option('dry-run', { + .global("no-input") + .option("dry-run", { boolean: true, coerce: once(processDryRun), default: false, - describe: 'Dry run mode: do not perform any real actions', + describe: "Dry run mode: do not perform any real actions", }) - .global('dry-run') + .global("dry-run") .strict() .showHelpOnFail(true) .parse(); diff --git a/src/logger.ts b/src/logger.ts index adabf02b..0e6b6052 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,6 +1,6 @@ -import { addBreadcrumb, Severity } from '@sentry/node'; -import Table = require('cli-table'); -import consola = require('consola'); +import { addBreadcrumb, Severity } from "@sentry/node"; +import Table = require("cli-table"); +import consola = require("consola"); /** * Format a list as a table @@ -61,7 +61,7 @@ class SentryBreadcrumbReporter { * Read logging level from the environment and return the appropriate enum value */ function getLogLevelFromEnv(): LOG_LEVEL { - const logLevelName = (process.env.CRAFT_LOG_LEVEL || '').toUpperCase(); + const logLevelName = (process.env.CRAFT_LOG_LEVEL || "").toUpperCase(); const logLevelNumber = LOG_LEVEL[logLevelName as keyof typeof LOG_LEVEL]; return logLevelNumber ?? consola.level; } @@ -82,7 +82,7 @@ let initialized = false; */ export function init(logLevel?: LOG_LEVEL): Logger { if (initialized) { - consola.warn('Logger already initialized, ignoring duplicate init.'); + consola.warn("Logger already initialized, ignoring duplicate init."); } setLogLevel(logLevel !== undefined ? logLevel : getLogLevelFromEnv()); diff --git a/src/schemas/projectConfig.schema.ts b/src/schemas/projectConfig.schema.ts index c069c9e8..5e44e72f 100644 --- a/src/schemas/projectConfig.schema.ts +++ b/src/schemas/projectConfig.schema.ts @@ -4,110 +4,110 @@ */ const projectConfigJsonSchema = { - title: 'CraftProjectConfig', - description: 'Craft project-specific configuration', - type: 'object', + title: "CraftProjectConfig", + description: "Craft project-specific configuration", + type: "object", properties: { github: { - title: 'GithubGlobalConfig', - description: 'Global (non-target!) GitHub configuration for the project', - type: 'object', + title: "GithubGlobalConfig", + description: "Global (non-target!) GitHub configuration for the project", + type: "object", properties: { owner: { - type: 'string', + type: "string", }, repo: { - type: 'string', + type: "string", }, }, additionalProperties: false, - required: ['owner', 'repo'], + required: ["owner", "repo"], }, targets: { - type: 'array', - items: { $ref: '#/definitions/targetConfig' }, + type: "array", + items: { $ref: "#/definitions/targetConfig" }, }, - preReleaseCommand: { type: 'string' }, - postReleaseCommand: { type: 'string' }, - releaseBranchPrefix: { type: 'string' }, - changelog: { type: 'string' }, + preReleaseCommand: { type: "string" }, + postReleaseCommand: { type: "string" }, + releaseBranchPrefix: { type: "string" }, + changelog: { type: "string" }, changelogPolicy: { - title: 'ChangelogPolicy', - description: 'Different policies for changelog management', - type: 'string', - enum: ['auto', 'simple', 'none'], - tsEnumNames: ['Auto', 'Simple', 'None'], + title: "ChangelogPolicy", + description: "Different policies for changelog management", + type: "string", + enum: ["auto", "simple", "none"], + tsEnumNames: ["Auto", "Simple", "None"], }, minVersion: { - type: 'string', - pattern: '^\\d+\\.\\d+\\.\\d+.*$', + type: "string", + pattern: "^\\d+\\.\\d+\\.\\d+.*$", }, requireNames: { - type: 'array', - items: { type: 'string' }, + type: "array", + items: { type: "string" }, }, statusProvider: { - title: 'BaseStatusProvider', - description: 'Which service should be used for status checks', - type: 'object', + title: "BaseStatusProvider", + description: "Which service should be used for status checks", + type: "object", properties: { name: { - title: 'StatusProviderName', - description: 'Name of the status provider', - type: 'string', - enum: ['zeus', 'github'], - tsEnumNames: ['Zeus', 'Github'], + title: "StatusProviderName", + description: "Name of the status provider", + type: "string", + enum: ["zeus", "github"], + tsEnumNames: ["Zeus", "Github"], }, config: { - type: 'object', + type: "object", }, }, additionalProperties: false, - required: ['name'], + required: ["name"], }, artifactProvider: { - title: 'BaseArtifactProvider', - description: 'Which service should be used for artifact storage', - type: 'object', + title: "BaseArtifactProvider", + description: "Which service should be used for artifact storage", + type: "object", properties: { name: { - title: 'ArtifactProviderName', - description: 'Name of the artifact provider', - type: 'string', - enum: ['zeus', 'gcs', 'github', 'none'], - tsEnumNames: ['Zeus', 'GCS', 'Github', 'None'], + title: "ArtifactProviderName", + description: "Name of the artifact provider", + type: "string", + enum: ["zeus", "gcs", "github", "none"], + tsEnumNames: ["Zeus", "GCS", "Github", "None"], }, config: { - type: 'object', + type: "object", }, }, additionalProperties: false, - required: ['name'], + required: ["name"], }, }, additionalProperties: false, - required: ['github'], + required: ["github"], definitions: { targetConfig: { - title: 'TargetConfig', - description: 'Generic target configuration', - type: 'object', + title: "TargetConfig", + description: "Generic target configuration", + type: "object", properties: { name: { - type: 'string', + type: "string", }, id: { - type: 'string', + type: "string", }, includeNames: { - type: 'string', + type: "string", }, excludeNames: { - type: 'string', + type: "string", }, }, - required: ['name'], + required: ["name"], }, /** @@ -132,36 +132,36 @@ const projectConfigJsonSchema = { * */ githubConfig: { - title: 'GithubTargetConfig', - description: 'Configuration options for the Github target', - extends: { $ref: '#/definitions/targetConfig' }, + title: "GithubTargetConfig", + description: "Configuration options for the Github target", + extends: { $ref: "#/definitions/targetConfig" }, properties: { changelog: { - type: 'string', + type: "string", }, - name: { type: 'string', enum: ['github'] }, + name: { type: "string", enum: ["github"] }, }, - required: ['name'], + required: ["name"], additionalProperties: false, }, npmConfig: { - title: 'NpmTargetConfig', - description: 'Configuration options for the NPM target', - extends: { $ref: '#/definitions/targetConfig' }, + title: "NpmTargetConfig", + description: "Configuration options for the NPM target", + extends: { $ref: "#/definitions/targetConfig" }, properties: { access: { - type: 'string', + type: "string", }, }, additionalProperties: false, }, cratesConfig: { - title: 'CratesTargetConfig', - description: 'Configuration options for the Crates target', - extends: { $ref: '#/definitions/targetConfig' }, + title: "CratesTargetConfig", + description: "Configuration options for the Crates target", + extends: { $ref: "#/definitions/targetConfig" }, properties: { noDevDeps: { - type: 'boolean', + type: "boolean", }, }, additionalProperties: false, diff --git a/src/schemas/project_config.ts b/src/schemas/project_config.ts index 9a62a9e5..4571f552 100644 --- a/src/schemas/project_config.ts +++ b/src/schemas/project_config.ts @@ -60,23 +60,23 @@ export interface BaseArtifactProvider { * Different policies for changelog management */ export const enum ChangelogPolicy { - Auto = 'auto', - Simple = 'simple', - None = 'none', + Auto = "auto", + Simple = "simple", + None = "none", } /** * Name of the status provider */ export const enum StatusProviderName { - Zeus = 'zeus', - Github = 'github', + Zeus = "zeus", + Github = "github", } /** * Name of the artifact provider */ export const enum ArtifactProviderName { - Zeus = 'zeus', - GCS = 'gcs', - Github = 'github', - None = 'none', + Zeus = "zeus", + GCS = "gcs", + Github = "github", + None = "none", } diff --git a/src/status_providers/base.ts b/src/status_providers/base.ts index 8c62ae09..a4dda205 100644 --- a/src/status_providers/base.ts +++ b/src/status_providers/base.ts @@ -1,10 +1,10 @@ -import ora from 'ora'; +import ora from "ora"; -import { sleepAsync } from '../utils/system'; +import { sleepAsync } from "../utils/system"; -import { reportError } from '../utils/errors'; +import { reportError } from "../utils/errors"; -import { logger } from '../logger'; +import { logger } from "../logger"; /** Max number of seconds to wait for the build to finish */ const BUILD_STATUS_POLLING_MAX = 60 * 60; @@ -17,13 +17,13 @@ const BUILD_POLLING_INTERVAL = 30; */ export enum CommitStatus { /** Commit is still being tested/checked/etc. */ - PENDING = 'pending', + PENDING = "pending", /** All required commit checks have passed successfully */ - SUCCESS = 'success', + SUCCESS = "success", /** One or more commit checks failed */ - FAILURE = 'failure', + FAILURE = "failure", /** Commit could not be found */ - NOT_FOUND = 'not_found', + NOT_FOUND = "not_found", } /** Repository information */ @@ -55,7 +55,7 @@ export abstract class BaseStatusProvider { */ public async waitForTheBuildToSucceed(revision: string): Promise { // Status spinner - const spinner = ora({ spinner: 'bouncingBar' }) as any; + const spinner = ora({ spinner: "bouncingBar" }) as any; let secondsPassed = 0; let firstIteration = true; @@ -104,8 +104,8 @@ export abstract class BaseStatusProvider { // Format as "YYYY-MM-DD hh:mm:ss" const timeString = new Date() .toISOString() - .replace(/T/, ' ') - .replace(/\..+/, ''); + .replace(/T/, " ") + .replace(/\..+/, ""); // Update the spinner const waitMessage = `[${timeString}] CI builds are still in progress, sleeping for ${BUILD_POLLING_INTERVAL} seconds...`; spinner.text = waitMessage; diff --git a/src/status_providers/github.ts b/src/status_providers/github.ts index 2dc75a07..5168b0f8 100644 --- a/src/status_providers/github.ts +++ b/src/status_providers/github.ts @@ -1,10 +1,10 @@ -import * as Github from '@octokit/rest'; +import * as Github from "@octokit/rest"; -import { logger } from '../logger'; -import { BaseStatusProvider, CommitStatus, RepositoryInfo } from './base'; -import { getGithubClient } from '../utils/githubApi'; -import { ConfigurationError } from '../utils/errors'; -import { formatJson } from '../utils/strings'; +import { logger } from "../logger"; +import { BaseStatusProvider, CommitStatus, RepositoryInfo } from "./base"; +import { getGithubClient } from "../utils/githubApi"; +import { ConfigurationError } from "../utils/errors"; +import { formatJson } from "../utils/strings"; /** * Status provider that talks to GitHub to get commit checks (statuses) @@ -74,34 +74,34 @@ export class GithubStatusProvider extends BaseStatusProvider { return contextResult; } } - logger.debug('All contexts concluded successfully!'); + logger.debug("All contexts concluded successfully!"); return CommitStatus.SUCCESS; } else { logger.debug( - 'No config provided for Github status provider, calculating the combined status...' + "No config provided for Github status provider, calculating the combined status..." ); let commitApiStatusResult; if ( revisionStatus.total_count === 0 && - revisionStatus.state === 'pending' + revisionStatus.state === "pending" ) { // Edge case, this is what GitHub returns when there are no registered legacy checks. - logger.debug('No legacy checks detected, checking for runs...'); + logger.debug("No legacy checks detected, checking for runs..."); const hasPendingActiveSuites = revisionCheckSuites.check_suites.some( - suite => + (suite) => // Need the any cast as octokit lacks this prop in its types (suite as any).latest_check_runs_count > 0 && - suite.status === 'queued' + suite.status === "queued" ); if (revisionChecks.total_count > 0) { - logger.debug('Check runs exist, continuing...'); + logger.debug("Check runs exist, continuing..."); commitApiStatusResult = CommitStatus.SUCCESS; } else if (hasPendingActiveSuites) { - logger.debug('Pending check suites exist, continuing...'); + logger.debug("Pending check suites exist, continuing..."); commitApiStatusResult = CommitStatus.PENDING; } else { - logger.warn('No valid build contexts detected, did any checks run?'); + logger.warn("No valid build contexts detected, did any checks run?"); commitApiStatusResult = CommitStatus.NOT_FOUND; } } else { @@ -156,14 +156,14 @@ export class GithubStatusProvider extends BaseStatusProvider { logger.debug(`Status check results: ${formatJson(results)}`); if (results.includes(CommitStatus.FAILURE)) { - logger.error('At least one of the checks has failed, result: FAILURE'); + logger.error("At least one of the checks has failed, result: FAILURE"); return CommitStatus.FAILURE; } else if (results.includes(CommitStatus.PENDING)) { - logger.debug('At least one of the checks is pending, result: PENDING'); + logger.debug("At least one of the checks is pending, result: PENDING"); return CommitStatus.PENDING; } else if ( results[0] === CommitStatus.NOT_FOUND && - results.every(el => el === results[0]) + results.every((el) => el === results[0]) ) { logger.error(`Context "${context}" was not found, result: FAILURE`); return CommitStatus.FAILURE; @@ -171,7 +171,7 @@ export class GithubStatusProvider extends BaseStatusProvider { logger.debug(`Context "${context}" was build succesffully!`); return CommitStatus.SUCCESS; } else { - throw new Error('Unreachable'); + throw new Error("Unreachable"); } } @@ -181,9 +181,9 @@ export class GithubStatusProvider extends BaseStatusProvider { * @param state Status string */ private stateToCommitStatus(state: string): CommitStatus { - if (state === 'success') { + if (state === "success") { return CommitStatus.SUCCESS; - } else if (state === 'pending') { + } else if (state === "pending") { return CommitStatus.PENDING; } else { return CommitStatus.FAILURE; @@ -227,17 +227,17 @@ export class GithubStatusProvider extends BaseStatusProvider { ): CommitStatus { // Check runs: we have an array of runs, and each of them has a status let isSomethingPending = revisionCheckSuites.check_suites.some( - suite => + (suite) => // Need the any cast as octokit lacks this prop in its types - (suite as any).latest_check_runs_count > 0 && suite.status === 'queued' + (suite as any).latest_check_runs_count > 0 && suite.status === "queued" ); let found = false; for (const run of revisionChecks.check_runs) { if (context && run.name !== context) { continue; } - if (run.status === 'completed') { - if (run.conclusion !== 'success' && run.conclusion !== 'skipped') { + if (run.status === "completed") { + if (run.conclusion !== "success" && run.conclusion !== "skipped") { return CommitStatus.FAILURE; } } else { diff --git a/src/status_providers/zeus.ts b/src/status_providers/zeus.ts index f396668d..dd719347 100644 --- a/src/status_providers/zeus.ts +++ b/src/status_providers/zeus.ts @@ -1,5 +1,5 @@ -import { BaseStatusProvider, CommitStatus, RepositoryInfo } from './base'; -import { ZeusStore } from '../stores/zeus'; +import { BaseStatusProvider, CommitStatus, RepositoryInfo } from "./base"; +import { ZeusStore } from "../stores/zeus"; /** * TODO @@ -28,7 +28,7 @@ export class ZeusStatusProvider extends BaseStatusProvider { try { zeusRevision = await this.store.getRevision(revision); } catch (e) { - const errorMessage: string = e.message || ''; + const errorMessage: string = e.message || ""; if (errorMessage.match(/404 not found|resource not found/i)) { return CommitStatus.NOT_FOUND; } diff --git a/src/stores/__tests__/zeus.test.ts b/src/stores/__tests__/zeus.test.ts index 7b398191..0e6a1eef 100644 --- a/src/stores/__tests__/zeus.test.ts +++ b/src/stores/__tests__/zeus.test.ts @@ -1,8 +1,8 @@ -import { Artifact, Status } from '@zeus-ci/sdk'; +import { Artifact, Status } from "@zeus-ci/sdk"; -jest.mock('../../utils/env'); +jest.mock("../../utils/env"); -import { ZeusStore } from '../zeus'; +import { ZeusStore } from "../zeus"; // TODO (kmclb) move these tests over to the artifact provider test folder @@ -11,90 +11,92 @@ function artifactFactory( options?: Record ): Artifact { return { - download_url: 'http://invalid', + download_url: "http://invalid", file: { - name: 'test', + name: "test", size: 100, }, id: name, name, status: Status.FINISHED, - type: 'test/test', + type: "test/test", ...options, }; } -const REPO_OWNER = 'craft-test-owner'; -const REPO_NAME = 'craft-test'; +const REPO_OWNER = "craft-test-owner"; +const REPO_NAME = "craft-test"; -describe('filterArtifactsForRevision', () => { +describe("filterArtifactsForRevision", () => { const zeusStore = new ZeusStore(REPO_OWNER, REPO_NAME); const artifactList = [ - 'test1.zip', - 'test2.exe', - 'test3.tgz', - 'smthelse', - ].map(name => artifactFactory(name, undefined)); - zeusStore.listArtifactsForRevision = jest.fn(async _revision => artifactList); - const revision = '1234567'; + "test1.zip", + "test2.exe", + "test3.tgz", + "smthelse", + ].map((name) => artifactFactory(name, undefined)); + zeusStore.listArtifactsForRevision = jest.fn( + async (_revision) => artifactList + ); + const revision = "1234567"; beforeEach(() => { jest.clearAllMocks(); }); - test('does not change the list if no arguments provided', async () => { + test("does not change the list if no arguments provided", async () => { const filtered = await zeusStore.filterArtifactsForRevision(revision); expect(filtered).toBe(artifactList); }); - test('uses includeNames', async () => { + test("uses includeNames", async () => { const filtered = await zeusStore.filterArtifactsForRevision(revision, { includeNames: /.exe$/, }); - expect(filtered).toEqual([artifactFactory('test2.exe')]); + expect(filtered).toEqual([artifactFactory("test2.exe")]); }); - test('uses excludeNames', async () => { + test("uses excludeNames", async () => { const filtered = await zeusStore.filterArtifactsForRevision(revision, { excludeNames: /^test.*$/, }); - expect(filtered).toEqual([artifactFactory('smthelse')]); + expect(filtered).toEqual([artifactFactory("smthelse")]); }); - test('uses both includeNames and excludeNames', async () => { + test("uses both includeNames and excludeNames", async () => { const filtered = await zeusStore.filterArtifactsForRevision(revision, { excludeNames: /(exe|zip)$/, includeNames: /^test/, }); - expect(filtered).toEqual([artifactFactory('test3.tgz')]); + expect(filtered).toEqual([artifactFactory("test3.tgz")]); }); }); -describe('filterArtifactsForRevision', () => { +describe("filterArtifactsForRevision", () => { const zeusStore = new ZeusStore(REPO_OWNER, REPO_NAME); const artifactList = [ - 'test1.zip', - 'test2.exe', - 'test3.tgz', - 'smthelse', - ].map(name => artifactFactory(name, undefined)); + "test1.zip", + "test2.exe", + "test3.tgz", + "smthelse", + ].map((name) => artifactFactory(name, undefined)); zeusStore.client.listArtifactsForRevision = jest .fn() .mockReturnValue(artifactList); const mockClientListArtifacts = zeusStore.client .listArtifactsForRevision as jest.Mock; - const revision = '1234567'; + const revision = "1234567"; beforeEach(() => { jest.clearAllMocks(); zeusStore.clearStoreCaches(); }); - test('calls Zeus client with proper arguments', async () => { + test("calls Zeus client with proper arguments", async () => { const result = await zeusStore.listArtifactsForRevision(revision); expect(result).toEqual(artifactList); @@ -105,7 +107,7 @@ describe('filterArtifactsForRevision', () => { ); }); - test('caches results', async () => { + test("caches results", async () => { const result1 = await zeusStore.listArtifactsForRevision(revision); const result2 = await zeusStore.listArtifactsForRevision(revision); @@ -113,20 +115,20 @@ describe('filterArtifactsForRevision', () => { expect(mockClientListArtifacts).toHaveBeenCalledTimes(1); }); - test('picks only the most recent artifact in case there are duplicated names', async () => { - const name = 'file.zip'; + test("picks only the most recent artifact in case there are duplicated names", async () => { + const name = "file.zip"; const artifacts = [ artifactFactory(name, { - id: '1', - updated_at: '2018-01-01T00:00:10.000000+00:00', + id: "1", + updated_at: "2018-01-01T00:00:10.000000+00:00", }), artifactFactory(name, { - id: '2', - updated_at: '2018-11-11T00:55:55.999999+00:00', + id: "2", + updated_at: "2018-11-11T00:55:55.999999+00:00", }), artifactFactory(name, { - id: '3', - updated_at: 'invalid', + id: "3", + updated_at: "invalid", }), ]; mockClientListArtifacts.mockReturnValue(artifacts); diff --git a/src/stores/zeus.ts b/src/stores/zeus.ts index 5eb4c931..ee06c5d9 100644 --- a/src/stores/zeus.ts +++ b/src/stores/zeus.ts @@ -5,17 +5,17 @@ import { RevisionInfo, Status, RepositoryInfo, -} from '@zeus-ci/sdk'; -import * as _ from 'lodash'; +} from "@zeus-ci/sdk"; +import * as _ from "lodash"; -import { checkEnvForPrerequisite } from '../utils/env'; +import { checkEnvForPrerequisite } from "../utils/env"; import { calculateChecksum, HashAlgorithm, HashOutputFormat, -} from '../utils/system'; -import { clearObjectProperties } from '../utils/objects'; -import { logger } from '../logger'; +} from "../utils/system"; +import { clearObjectProperties } from "../utils/objects"; +import { logger } from "../logger"; // TODO (kmclb) get rid of this file once artifact providers are done @@ -66,8 +66,8 @@ export class ZeusStore { downloadDirectory?: string ) { checkEnvForPrerequisite({ - legacyName: 'ZEUS_TOKEN', - name: 'ZEUS_API_TOKEN', + legacyName: "ZEUS_TOKEN", + name: "ZEUS_API_TOKEN", }); // We currently need ZEUS_TOKEN set for zeus-sdk to work properly if (!process.env.ZEUS_TOKEN) { @@ -118,7 +118,7 @@ export class ZeusStore { */ public async downloadArtifacts(artifacts: Artifact[]): Promise { return Promise.all( - artifacts.map(async artifact => this.downloadArtifact(artifact)) + artifacts.map(async (artifact) => this.downloadArtifact(artifact)) ); } @@ -143,16 +143,18 @@ export class ZeusStore { ); // For every filename, take the artifact with the most recent update time - const nameToArtifacts = _.groupBy(artifacts, artifact => artifact.name); - const filteredArtifacts = Object.keys(nameToArtifacts).map(artifactName => { - const artifactObjects = nameToArtifacts[artifactName]; - // Sort by the update time - const sortedArtifacts = _.sortBy( - artifactObjects, - artifact => Date.parse(artifact.updated_at || '') || 0 - ); - return sortedArtifacts[sortedArtifacts.length - 1]; - }); + const nameToArtifacts = _.groupBy(artifacts, (artifact) => artifact.name); + const filteredArtifacts = Object.keys(nameToArtifacts).map( + (artifactName) => { + const artifactObjects = nameToArtifacts[artifactName]; + // Sort by the update time + const sortedArtifacts = _.sortBy( + artifactObjects, + (artifact) => Date.parse(artifact.updated_at || "") || 0 + ); + return sortedArtifacts[sortedArtifacts.length - 1]; + } + ); this.fileListCache[revision] = filteredArtifacts; return filteredArtifacts; @@ -174,13 +176,13 @@ export class ZeusStore { } const { includeNames, excludeNames } = filterOptions; if (includeNames) { - filteredArtifacts = filteredArtifacts.filter(artifact => + filteredArtifacts = filteredArtifacts.filter((artifact) => includeNames.test(artifact.name) ); } if (excludeNames) { filteredArtifacts = filteredArtifacts.filter( - artifact => !excludeNames.test(artifact.name) + (artifact) => !excludeNames.test(artifact.name) ); } return filteredArtifacts; diff --git a/src/targets/__tests__/awsLambda.test.ts b/src/targets/__tests__/awsLambda.test.ts index fb3c9922..d33071f4 100644 --- a/src/targets/__tests__/awsLambda.test.ts +++ b/src/targets/__tests__/awsLambda.test.ts @@ -1,39 +1,39 @@ -import { NoneArtifactProvider } from '../../artifact_providers/none'; -import { ConfigurationError } from '../../utils/errors'; -import { AwsLambdaLayerTarget } from '../awsLambdaLayer'; +import { NoneArtifactProvider } from "../../artifact_providers/none"; +import { ConfigurationError } from "../../utils/errors"; +import { AwsLambdaLayerTarget } from "../awsLambdaLayer"; -jest.mock('fs'); +jest.mock("fs"); /** Returns a new AwsLambdaLayerTarget test instance. */ function getAwsLambdaTarget(): AwsLambdaLayerTarget { return new AwsLambdaLayerTarget( { - name: 'aws-lambda-layer', - ['testKey']: 'testValue', + name: "aws-lambda-layer", + ["testKey"]: "testValue", }, new NoneArtifactProvider() ); } function setAwsEnvironmentVariables() { - process.env.AWS_ACCESS_KEY_ID = 'test aws access key'; - process.env.AWS_SECRET_ACCESS_KEY = 'test aws secret access key'; - process.env.GITHUB_TOKEN = 'test github token'; - process.env.GITHUB_API_TOKEN = 'test github api token'; + process.env.AWS_ACCESS_KEY_ID = "test aws access key"; + process.env.AWS_SECRET_ACCESS_KEY = "test aws secret access key"; + process.env.GITHUB_TOKEN = "test github token"; + process.env.GITHUB_API_TOKEN = "test github api token"; } function setTestingProjectConfig(awsTarget: AwsLambdaLayerTarget) { - awsTarget.config.layerName = 'testLayerName'; + awsTarget.config.layerName = "testLayerName"; awsTarget.config.compatibleRuntimes = [ { - name: 'runtimeTestName', - versions: ['nodejs10.x', 'nodejs12.x'], + name: "runtimeTestName", + versions: ["nodejs10.x", "nodejs12.x"], }, ]; - awsTarget.config.license = 'MIT'; + awsTarget.config.license = "MIT"; } -describe('get aws config environment variables', () => { +describe("get aws config environment variables", () => { const oldEnvVariables = process.env; beforeEach(() => { @@ -46,15 +46,15 @@ describe('get aws config environment variables', () => { }); function deleteTargetOptionsFromEnvironment() { - if ('AWS_ACCESS_KEY_ID' in process.env) { + if ("AWS_ACCESS_KEY_ID" in process.env) { delete process.env.AWS_ACCESS_KEY_ID; } - if ('AWS_SECRET_ACCESES_KEY' in process.env) { + if ("AWS_SECRET_ACCESES_KEY" in process.env) { delete process.env.AWS_SECRET_ACCESES_KEY; } } - test('errors on missing environment variables', () => { + test("errors on missing environment variables", () => { deleteTargetOptionsFromEnvironment(); try { getAwsLambdaTarget(); @@ -63,7 +63,7 @@ describe('get aws config environment variables', () => { } }); - test('success on environment variables', () => { + test("success on environment variables", () => { deleteTargetOptionsFromEnvironment(); setAwsEnvironmentVariables(); // AwsLambdaTarget needs the environment variables to initialize. @@ -71,7 +71,7 @@ describe('get aws config environment variables', () => { }); }); -describe('project config parameters', () => { +describe("project config parameters", () => { beforeAll(() => { setAwsEnvironmentVariables(); }); @@ -82,11 +82,11 @@ describe('project config parameters', () => { delete awsTarget.config.license; } - test('missing config parameters', async () => { + test("missing config parameters", async () => { const awsTarget = getAwsLambdaTarget(); clearConfig(awsTarget); try { - await awsTarget.publish('', ''); + await awsTarget.publish("", ""); } catch (error) { expect(error instanceof ConfigurationError).toBe(true); expect( @@ -95,10 +95,10 @@ describe('project config parameters', () => { } }); - test('correct config', async () => { + test("correct config", async () => { const awsTarget = getAwsLambdaTarget(); setTestingProjectConfig(awsTarget); - const failingTestErrorMsg = 'failing mock test'; + const failingTestErrorMsg = "failing mock test"; const getArtifactsFailingMock = jest.fn().mockImplementation(() => { throw new Error(failingTestErrorMsg); }); @@ -111,24 +111,24 @@ describe('project config parameters', () => { awsTarget.getArtifactsForRevision = getArtifactsFailingMock.bind( AwsLambdaLayerTarget ); - await awsTarget.publish('', ''); // Should break the mocked function. - fail('Should not reach here'); + await awsTarget.publish("", ""); // Should break the mocked function. + fail("Should not reach here"); } catch (error) { expect(new RegExp(failingTestErrorMsg).test(error.message)).toBe(true); } }); }); -describe('publish', () => { +describe("publish", () => { beforeAll(() => { setAwsEnvironmentVariables(); }); - const noArtifactsForRevision = jest.fn().mockImplementation(function() { + const noArtifactsForRevision = jest.fn().mockImplementation(function () { return []; }); - test('error on missing artifact', async () => { + test("error on missing artifact", async () => { const awsTarget = getAwsLambdaTarget(); setTestingProjectConfig(awsTarget); awsTarget.getArtifactsForRevision = noArtifactsForRevision.bind( @@ -138,7 +138,7 @@ describe('publish', () => { // thrown; when it's on dry run, the error is logged and `undefined` is // returned. Thus, both alternatives have been considered. try { - const noPackageFound = await awsTarget.publish('version', 'revision'); + const noPackageFound = await awsTarget.publish("version", "revision"); expect(noPackageFound).toBe(undefined); } catch (error) { expect(error instanceof Error).toBe(true); @@ -147,11 +147,11 @@ describe('publish', () => { } }); - const twoArtifactsForRevision = jest.fn().mockImplementation(function() { - return ['file1', 'file2']; + const twoArtifactsForRevision = jest.fn().mockImplementation(function () { + return ["file1", "file2"]; }); - test('error on having too many artifacts', async () => { + test("error on having too many artifacts", async () => { const awsTarget = getAwsLambdaTarget(); setTestingProjectConfig(awsTarget); awsTarget.getArtifactsForRevision = twoArtifactsForRevision.bind( @@ -162,8 +162,8 @@ describe('publish', () => { // returned. Thus, both alternatives have been considered. try { const multiplePackagesFound = await awsTarget.publish( - 'version', - 'revision' + "version", + "revision" ); expect(multiplePackagesFound).toBe(undefined); } catch (error) { diff --git a/src/targets/__tests__/crates.test.ts b/src/targets/__tests__/crates.test.ts index f44c9a20..33b5a4f5 100644 --- a/src/targets/__tests__/crates.test.ts +++ b/src/targets/__tests__/crates.test.ts @@ -1,15 +1,15 @@ -import { CrateDependency, CratePackage, CratesTarget } from '../crates'; -import { NoneArtifactProvider } from '../../artifact_providers/none'; +import { CrateDependency, CratePackage, CratesTarget } from "../crates"; +import { NoneArtifactProvider } from "../../artifact_providers/none"; -jest.mock('../../utils/system'); +jest.mock("../../utils/system"); function cratePackageFactory(name: string): CratePackage { return { dependencies: [], id: name, - manifest_path: '', + manifest_path: "", name, - version: '1.0.0', + version: "1.0.0", publish: null, }; } @@ -17,7 +17,7 @@ function cratePackageFactory(name: string): CratePackage { function cratePackageToDependency(cratePackage: CratePackage): CrateDependency { return { name: cratePackage.name, - req: '1.0.0', + req: "1.0.0", kind: null, }; } @@ -25,22 +25,22 @@ function cratePackageToDependency(cratePackage: CratePackage): CrateDependency { function makeDev(dependency: CrateDependency): CrateDependency { return { ...dependency, - kind: 'dev', + kind: "dev", }; } -describe('getPublishOrder', () => { - process.env.CRATES_IO_TOKEN = 'xxx'; +describe("getPublishOrder", () => { + process.env.CRATES_IO_TOKEN = "xxx"; const target = new CratesTarget( { - name: 'crates', + name: "crates", noDevDeps: true, }, new NoneArtifactProvider() ); - test('sorts crate packages properly', () => { - const packages = ['p1', 'p2', 'p3', 'p4'].map(cratePackageFactory); + test("sorts crate packages properly", () => { + const packages = ["p1", "p2", "p3", "p4"].map(cratePackageFactory); const [p1, p2, p3, p4] = packages; p1.dependencies = [p2, p3].map(cratePackageToDependency); p3.dependencies = [p4].map(cratePackageToDependency); @@ -49,13 +49,13 @@ describe('getPublishOrder', () => { expect(target.getPublishOrder(packages)).toEqual(sortedPackages); }); - test('does not fail on a single package', () => { - const packages = [cratePackageFactory('p1')]; + test("does not fail on a single package", () => { + const packages = [cratePackageFactory("p1")]; expect(target.getPublishOrder(packages)).toEqual(packages); }); - test('errors on circular dependencies', () => { - const packages = ['p1', 'p2'].map(cratePackageFactory); + test("errors on circular dependencies", () => { + const packages = ["p1", "p2"].map(cratePackageFactory); const [p1, p2] = packages; p1.dependencies = [cratePackageToDependency(p2)]; @@ -64,8 +64,8 @@ describe('getPublishOrder', () => { expect(() => target.getPublishOrder(packages)).toThrowError(Error); }); - test('excludes dev dependencies', () => { - const packages = ['p1', 'p2'].map(cratePackageFactory); + test("excludes dev dependencies", () => { + const packages = ["p1", "p2"].map(cratePackageFactory); const [p1, p2] = packages; p1.dependencies = [cratePackageToDependency(p2)]; diff --git a/src/targets/__tests__/index.test.ts b/src/targets/__tests__/index.test.ts index 85efc3b3..2d773e7f 100644 --- a/src/targets/__tests__/index.test.ts +++ b/src/targets/__tests__/index.test.ts @@ -1,14 +1,14 @@ -import { getAllTargetNames, getTargetByName } from '..'; -import { GithubTarget } from '../github'; +import { getAllTargetNames, getTargetByName } from ".."; +import { GithubTarget } from "../github"; -describe('getTargetByName', () => { - test('converts target name to class', () => { - expect(getTargetByName('github')).toBe(GithubTarget); +describe("getTargetByName", () => { + test("converts target name to class", () => { + expect(getTargetByName("github")).toBe(GithubTarget); }); }); -describe('getAllTargetNames', () => { - test('retrieves all target names', () => { - expect(getAllTargetNames()).toContain('github'); +describe("getAllTargetNames", () => { + test("retrieves all target names", () => { + expect(getAllTargetNames()).toContain("github"); }); }); diff --git a/src/targets/awsLambdaLayer.ts b/src/targets/awsLambdaLayer.ts index c9edd513..92fbaabc 100644 --- a/src/targets/awsLambdaLayer.ts +++ b/src/targets/awsLambdaLayer.ts @@ -1,32 +1,32 @@ -import * as fs from 'fs'; -import * as path from 'path'; +import * as fs from "fs"; +import * as path from "path"; -import * as Github from '@octokit/rest'; -import simpleGit from 'simple-git'; +import * as Github from "@octokit/rest"; +import simpleGit from "simple-git"; import { getAuthUsername, getGithubApiToken, getGithubClient, GithubRemote, -} from '../utils/githubApi'; +} from "../utils/githubApi"; -import { logger as loggerRaw } from '../logger'; -import { TargetConfig } from '../schemas/project_config'; -import { BaseTarget } from './base'; -import { BaseArtifactProvider } from '../artifact_providers/base'; -import { ConfigurationError, reportError } from '../utils/errors'; +import { logger as loggerRaw } from "../logger"; +import { TargetConfig } from "../schemas/project_config"; +import { BaseTarget } from "./base"; +import { BaseArtifactProvider } from "../artifact_providers/base"; +import { ConfigurationError, reportError } from "../utils/errors"; import { AwsLambdaLayerManager, CompatibleRuntime, extractRegionNames, getAccountFromArn, getRegionsFromAws, -} from '../utils/awsLambdaLayerManager'; -import { createSymlinks } from '../utils/symlink'; -import { withTempDir } from '../utils/files'; -import { isDryRun } from '../utils/helpers'; -import { isPreviewRelease } from '../utils/version'; -import { getRegistryGithubRemote } from '../utils/registry'; +} from "../utils/awsLambdaLayerManager"; +import { createSymlinks } from "../utils/symlink"; +import { withTempDir } from "../utils/files"; +import { isDryRun } from "../utils/helpers"; +import { isPreviewRelease } from "../utils/version"; +import { getRegistryGithubRemote } from "../utils/registry"; const logger = loggerRaw.withScope(`[aws-lambda-layer]`); @@ -49,15 +49,15 @@ interface AwsLambdaTargetConfig { */ export class AwsLambdaLayerTarget extends BaseTarget { /** Target name */ - public readonly name: string = 'aws-lambda-layer'; + public readonly name: string = "aws-lambda-layer"; /** Target options */ public readonly awsLambdaConfig: AwsLambdaTargetConfig; /** GitHub client. */ public readonly github: Github; /** The directory where the runtime-specific directories are. */ - private readonly AWS_REGISTRY_DIR = 'aws-lambda-layers'; + private readonly AWS_REGISTRY_DIR = "aws-lambda-layers"; /** File containing data fields every new version file overrides */ - private readonly BASE_FILENAME = 'base.json'; + private readonly BASE_FILENAME = "base.json"; public constructor( config: TargetConfig, @@ -93,18 +93,18 @@ export class AwsLambdaLayerTarget extends BaseTarget { */ private checkProjectConfig(): void { const missingConfigOptions = []; - if (!('layerName' in this.config)) { - missingConfigOptions.push('layerName'); + if (!("layerName" in this.config)) { + missingConfigOptions.push("layerName"); } - if (!('compatibleRuntimes' in this.config)) { - missingConfigOptions.push('compatibleRuntimes'); + if (!("compatibleRuntimes" in this.config)) { + missingConfigOptions.push("compatibleRuntimes"); } - if (!('license' in this.config)) { - missingConfigOptions.push('license'); + if (!("license" in this.config)) { + missingConfigOptions.push("license"); } if (missingConfigOptions.length > 0) { throw new ConfigurationError( - 'Missing project configuration parameter(s): ' + missingConfigOptions + "Missing project configuration parameter(s): " + missingConfigOptions ); } } @@ -117,7 +117,7 @@ export class AwsLambdaLayerTarget extends BaseTarget { public async publish(version: string, revision: string): Promise { this.checkProjectConfig(); - logger.debug('Fetching artifact list...'); + logger.debug("Fetching artifact list..."); const packageFiles = await this.getArtifactsForRevision(revision, { includeNames: this.config.includeNames === undefined @@ -126,13 +126,13 @@ export class AwsLambdaLayerTarget extends BaseTarget { }); if (packageFiles.length == 0) { - reportError('Cannot publish AWS Lambda Layer: no packages found'); + reportError("Cannot publish AWS Lambda Layer: no packages found"); return undefined; } else if (packageFiles.length > 1) { reportError( - 'Cannot publish AWS Lambda Layer: ' + - 'multiple packages with matching patterns were found. You may want ' + - 'to include or modify the includeNames parameter in the project config' + "Cannot publish AWS Lambda Layer: " + + "multiple packages with matching patterns were found. You may want " + + "to include or modify the includeNames parameter in the project config" ); return undefined; } @@ -142,14 +142,14 @@ export class AwsLambdaLayerTarget extends BaseTarget { ); const awsRegions = extractRegionNames(await getRegionsFromAws()); - logger.debug('AWS regions: ' + awsRegions); + logger.debug("AWS regions: " + awsRegions); const remote = this.awsLambdaConfig.registryRemote; const username = await getAuthUsername(this.github); remote.setAuth(username, getGithubApiToken()); await withTempDir( - async directory => { + async (directory) => { const git = simpleGit(directory); logger.info(`Cloning ${remote.getRemoteString()} to ${directory}...`); await git.clone(remote.getRemoteStringWithAuth(), directory); @@ -161,30 +161,30 @@ export class AwsLambdaLayerTarget extends BaseTarget { awsRegions, artifactBuffer ); - logger.debug('Finished publishing runtimes.'); + logger.debug("Finished publishing runtimes."); } else { - logger.info('[dry-run] Not publishing new layers.'); + logger.info("[dry-run] Not publishing new layers."); } - await git.add(['.']); - await git.checkout('master'); + await git.add(["."]); + await git.checkout("master"); const runtimeNames = this.config.compatibleRuntimes.map( (runtime: CompatibleRuntime) => runtime.name ); await git.commit( - 'craft(aws-lambda): AWS Lambda layers published\n\n' + + "craft(aws-lambda): AWS Lambda layers published\n\n" + `v${version} for ${runtimeNames}` ); if ( isPushableToRegistry(version, this.awsLambdaConfig.linkPrereleases) ) { - logger.info('Pushing changes...'); + logger.info("Pushing changes..."); await git.push(); } }, true, - 'craft-release-awslambdalayer-' + "craft-release-awslambdalayer-" ); } @@ -215,7 +215,7 @@ export class AwsLambdaLayerTarget extends BaseTarget { let publishedLayers = []; try { publishedLayers = await layerManager.publishToAllRegions(); - logger.debug('Finished publishing to all regions.'); + logger.debug("Finished publishing to all regions."); } catch (error) { logger.error( `Did not publish layers for ${runtime.name}. ` + @@ -247,7 +247,7 @@ export class AwsLambdaLayerTarget extends BaseTarget { return; } - const regionsVersions = publishedLayers.map(layer => { + const regionsVersions = publishedLayers.map((layer) => { return { region: layer.region, version: layer.version.toString(), @@ -302,11 +302,11 @@ function createVersionSymlinks( versionFilepath: string ): void { logger.debug(`Creating symlinks...`); - const latestVersionPath = path.posix.join(directory, 'latest.json'); + const latestVersionPath = path.posix.join(directory, "latest.json"); if (fs.existsSync(latestVersionPath)) { const previousVersion = fs .readlinkSync(latestVersionPath) - .split('.json')[0]; + .split(".json")[0]; createSymlinks(versionFilepath, version, previousVersion); } else { // When no previous versions are found, just create symlinks. @@ -330,7 +330,7 @@ function isPushableToRegistry( linkPrereleases: boolean ): boolean { if (isDryRun()) { - logger.info('[dry-run] Not pushing the branch.'); + logger.info("[dry-run] Not pushing the branch."); return false; } if (isPreviewRelease(version) && !linkPrereleases) { diff --git a/src/targets/base.ts b/src/targets/base.ts index 67288386..97a00e6e 100644 --- a/src/targets/base.ts +++ b/src/targets/base.ts @@ -1,11 +1,11 @@ -import { logger } from '../logger'; -import { TargetConfig } from '../schemas/project_config'; -import { FilterOptions } from '../stores/zeus'; -import { stringToRegexp } from '../utils/filters'; +import { logger } from "../logger"; +import { TargetConfig } from "../schemas/project_config"; +import { FilterOptions } from "../stores/zeus"; +import { stringToRegexp } from "../utils/filters"; import { BaseArtifactProvider, RemoteArtifact, -} from '../artifact_providers/base'; +} from "../artifact_providers/base"; // TODO: make abstract? /** @@ -13,7 +13,7 @@ import { */ export class BaseTarget { /** Target name */ - public readonly name: string = 'base'; + public readonly name: string = "base"; /** Artifact provider */ public readonly artifactProvider: BaseArtifactProvider; /** Unparsed target configuration */ @@ -47,7 +47,7 @@ export class BaseTarget { * @param revision Git commit SHA to be published */ public async publish(_version: string, _revision: string): Promise { - throw new Error('Not implemented'); + throw new Error("Not implemented"); return; } @@ -69,7 +69,7 @@ export class BaseTarget { }; // This is a hacky legacy way of skipping artifact downloads. // Can be removed when we fully migrate from ZeusStore to artifact providers. - if (filterOptions.includeNames?.source === 'none') { + if (filterOptions.includeNames?.source === "none") { logger.debug( `target.includeNames is 'none', skipping artifacts downloads.` ); diff --git a/src/targets/brew.ts b/src/targets/brew.ts index 8165a898..985f72ab 100644 --- a/src/targets/brew.ts +++ b/src/targets/brew.ts @@ -1,21 +1,21 @@ -import { mapLimit } from 'async'; -import * as Github from '@octokit/rest'; - -import { getGlobalGithubConfig } from '../config'; -import { logger as loggerRaw } from '../logger'; -import { GithubGlobalConfig, TargetConfig } from '../schemas/project_config'; -import { ConfigurationError } from '../utils/errors'; -import { getGithubClient } from '../utils/githubApi'; -import { isDryRun } from '../utils/helpers'; -import { renderTemplateSafe } from '../utils/strings'; -import { HashAlgorithm, HashOutputFormat } from '../utils/system'; -import { BaseTarget } from './base'; +import { mapLimit } from "async"; +import * as Github from "@octokit/rest"; + +import { getGlobalGithubConfig } from "../config"; +import { logger as loggerRaw } from "../logger"; +import { GithubGlobalConfig, TargetConfig } from "../schemas/project_config"; +import { ConfigurationError } from "../utils/errors"; +import { getGithubClient } from "../utils/githubApi"; +import { isDryRun } from "../utils/helpers"; +import { renderTemplateSafe } from "../utils/strings"; +import { HashAlgorithm, HashOutputFormat } from "../utils/system"; +import { BaseTarget } from "./base"; import { BaseArtifactProvider, MAX_DOWNLOAD_CONCURRENCY, -} from '../artifact_providers/base'; +} from "../artifact_providers/base"; -const logger = loggerRaw.withScope('[brew]'); +const logger = loggerRaw.withScope("[brew]"); /** * Regex used to parse homebrew taps (github repositories) @@ -47,7 +47,7 @@ export interface BrewTargetOptions { */ export class BrewTarget extends BaseTarget { /** Target name */ - public readonly name: string = 'brew'; + public readonly name: string = "brew"; /** Target options */ public readonly brewConfig: BrewTargetOptions; /** Github client */ @@ -97,8 +97,8 @@ export class BrewTarget extends BaseTarget { const { tap } = this.config; if (!tap) { return { - owner: 'homebrew', - repo: 'homebrew-core', + owner: "homebrew", + repo: "homebrew-core", }; } @@ -161,13 +161,13 @@ export class BrewTarget extends BaseTarget { // Format checksums and the tag version into the formula file const filesList = await this.getArtifactsForRevision(revision); logger.debug( - 'Downloading artifacts for the revision:', - JSON.stringify(filesList.map(file => file.filename)) + "Downloading artifacts for the revision:", + JSON.stringify(filesList.map((file) => file.filename)) ); const checksums: any = {}; - await mapLimit(filesList, MAX_DOWNLOAD_CONCURRENCY, async file => { + await mapLimit(filesList, MAX_DOWNLOAD_CONCURRENCY, async (file) => { checksums[file.filename] = await this.artifactProvider.getChecksum( file, HashAlgorithm.SHA256, @@ -185,17 +185,17 @@ export class BrewTarget extends BaseTarget { // Try to find the repository to publish in if (tapRepo.owner !== owner) { // TODO: Create a PR if we have no push rights to this repo - logger.warn('Skipping homebrew release: PRs not supported yet'); + logger.warn("Skipping homebrew release: PRs not supported yet"); return undefined; } const params = { - content: Buffer.from(data).toString('base64'), + content: Buffer.from(data).toString("base64"), message: `release: ${formulaName} ${version}`, owner: tapRepo.owner, path: formulaPath, repo: tapRepo.repo, - sha: (await this.getFormulaSha(formulaPath)) || '', + sha: (await this.getFormulaSha(formulaPath)) || "", }; logger.info( @@ -204,7 +204,7 @@ export class BrewTarget extends BaseTarget { `formula ${formulaName}` ); - const action = params.sha ? 'Updating' : 'Creating'; + const action = params.sha ? "Updating" : "Creating"; logger.debug( `${action} file ${params.owner}/${params.repo}:${params.path} (${params.sha})` ); @@ -214,6 +214,6 @@ export class BrewTarget extends BaseTarget { } else { logger.info(`[dry-run] Skipping file action: ${action}`); } - logger.info('Homebrew release complete'); + logger.info("Homebrew release complete"); } } diff --git a/src/targets/cocoapods.ts b/src/targets/cocoapods.ts index 923a046a..de6e1985 100644 --- a/src/targets/cocoapods.ts +++ b/src/targets/cocoapods.ts @@ -1,22 +1,22 @@ -import * as Github from '@octokit/rest'; -import * as fs from 'fs'; -import { basename, join } from 'path'; -import { promisify } from 'util'; - -import { getGlobalGithubConfig } from '../config'; -import { logger as loggerRaw } from '../logger'; -import { GithubGlobalConfig, TargetConfig } from '../schemas/project_config'; -import { ConfigurationError, reportError } from '../utils/errors'; -import { withTempDir } from '../utils/files'; -import { getFile, getGithubClient } from '../utils/githubApi'; -import { checkExecutableIsPresent, spawnProcess } from '../utils/system'; -import { BaseTarget } from './base'; -import { BaseArtifactProvider } from '../artifact_providers/base'; +import * as Github from "@octokit/rest"; +import * as fs from "fs"; +import { basename, join } from "path"; +import { promisify } from "util"; + +import { getGlobalGithubConfig } from "../config"; +import { logger as loggerRaw } from "../logger"; +import { GithubGlobalConfig, TargetConfig } from "../schemas/project_config"; +import { ConfigurationError, reportError } from "../utils/errors"; +import { withTempDir } from "../utils/files"; +import { getFile, getGithubClient } from "../utils/githubApi"; +import { checkExecutableIsPresent, spawnProcess } from "../utils/system"; +import { BaseTarget } from "./base"; +import { BaseArtifactProvider } from "../artifact_providers/base"; const writeFile = promisify(fs.writeFile); -const logger = loggerRaw.withScope('[cocoapods]'); +const logger = loggerRaw.withScope("[cocoapods]"); -const DEFAULT_COCOAPODS_BIN = 'pod'; +const DEFAULT_COCOAPODS_BIN = "pod"; /** * Command to launch cocoapods @@ -34,7 +34,7 @@ export interface CocoapodsTargetOptions { */ export class CocoapodsTarget extends BaseTarget { /** Target name */ - public readonly name: string = 'cocoapods'; + public readonly name: string = "cocoapods"; /** Target options */ public readonly cocoapodsConfig: CocoapodsTargetOptions; /** Github client */ @@ -59,7 +59,7 @@ export class CocoapodsTarget extends BaseTarget { public getCocoapodsConfig(): CocoapodsTargetOptions { const specPath = this.config.specPath; if (!specPath) { - throw new ConfigurationError('No podspec path provided!'); + throw new ConfigurationError("No podspec path provided!"); } return { @@ -94,15 +94,15 @@ export class CocoapodsTarget extends BaseTarget { const fileName = basename(specPath); await withTempDir( - async directory => { + async (directory) => { const filePath = join(directory, fileName); - await writeFile(filePath, specContents, 'utf8'); + await writeFile(filePath, specContents, "utf8"); logger.info(`Pushing podspec "${fileName}" to cocoapods...`); - await spawnProcess(COCOAPODS_BIN, ['setup']); + await spawnProcess(COCOAPODS_BIN, ["setup"]); await spawnProcess( COCOAPODS_BIN, - ['trunk', 'push', fileName, '--allow-warnings'], + ["trunk", "push", fileName, "--allow-warnings"], { cwd: directory, env: { @@ -112,9 +112,9 @@ export class CocoapodsTarget extends BaseTarget { ); }, true, - 'craft-cocoapods-' + "craft-cocoapods-" ); - logger.info('Cocoapods release complete'); + logger.info("Cocoapods release complete"); } } diff --git a/src/targets/crates.ts b/src/targets/crates.ts index 14d923d6..05bb28db 100644 --- a/src/targets/crates.ts +++ b/src/targets/crates.ts @@ -1,26 +1,26 @@ -import * as fs from 'fs'; -import * as path from 'path'; - -import * as _ from 'lodash'; -import simpleGit from 'simple-git'; - -import { getGlobalGithubConfig } from '../config'; -import { logger as loggerRaw } from '../logger'; -import { GithubGlobalConfig, TargetConfig } from '../schemas/project_config'; -import { forEachChained } from '../utils/async'; -import { ConfigurationError } from '../utils/errors'; -import { withTempDir } from '../utils/files'; +import * as fs from "fs"; +import * as path from "path"; + +import * as _ from "lodash"; +import simpleGit from "simple-git"; + +import { getGlobalGithubConfig } from "../config"; +import { logger as loggerRaw } from "../logger"; +import { GithubGlobalConfig, TargetConfig } from "../schemas/project_config"; +import { forEachChained } from "../utils/async"; +import { ConfigurationError } from "../utils/errors"; +import { withTempDir } from "../utils/files"; import { checkExecutableIsPresent, sleepAsync, spawnProcess, -} from '../utils/system'; -import { BaseTarget } from './base'; -import { BaseArtifactProvider } from '../artifact_providers/base'; +} from "../utils/system"; +import { BaseTarget } from "./base"; +import { BaseArtifactProvider } from "../artifact_providers/base"; -const logger = loggerRaw.withScope('[crates]'); +const logger = loggerRaw.withScope("[crates]"); -const DEFAULT_CARGO_BIN = 'cargo'; +const DEFAULT_CARGO_BIN = "cargo"; /** * Command to launch cargo @@ -32,7 +32,7 @@ const CARGO_BIN = process.env.CARGO_BIN || DEFAULT_CARGO_BIN; * dependency. This sometimes indicates a false positive if the cache has not * been updated. */ -const VERSION_ERROR = 'failed to select a version for the requirement'; +const VERSION_ERROR = "failed to select a version for the requirement"; /** * Maximum number of attempts including the initial one when publishing fails @@ -103,7 +103,7 @@ export interface CrateMetadata { */ export class CratesTarget extends BaseTarget { /** Target name */ - public readonly name: string = 'crates'; + public readonly name: string = "crates"; /** Target options */ public readonly cratesConfig: CratesTargetOptions; @@ -145,11 +145,11 @@ export class CratesTarget extends BaseTarget { */ public async getCrateMetadata(directory: string): Promise { const args = [ - 'metadata', - '--manifest-path', + "metadata", + "--manifest-path", `${directory}/Cargo.toml`, - '--no-deps', - '--format-version=1', + "--no-deps", + "--format-version=1", ]; logger.info(`Loading workspace information from ${directory}/Cargo.toml`); @@ -160,7 +160,7 @@ export class CratesTarget extends BaseTarget { { enableInDryRunMode: true } ); if (!metadata) { - throw new ConfigurationError('Empty Cargo metadata!'); + throw new ConfigurationError("Empty Cargo metadata!"); } return JSON.parse(metadata.toString()); } @@ -179,13 +179,13 @@ export class CratesTarget extends BaseTarget { * @returns The sorted list of packages */ public getPublishOrder(packages: CratePackage[]): CratePackage[] { - const remaining = _.keyBy(packages, p => p.name); + const remaining = _.keyBy(packages, (p) => p.name); const ordered: CratePackage[] = []; const isWorkspaceDependency = (dep: CrateDependency) => { // Optionally exclude dev dependencies from dependency resolution. When // this flag is provided, these usually lead to circular dependencies. - if (this.cratesConfig.noDevDeps && dep.kind === 'dev') { + if (this.cratesConfig.noDevDeps && dep.kind === "dev") { return false; } @@ -198,14 +198,14 @@ export class CratesTarget extends BaseTarget { const leafDependencies = _.filter( remaining, // Find all packages with no remaining workspace dependencies - p => p.dependencies.filter(isWorkspaceDependency).length === 0 + (p) => p.dependencies.filter(isWorkspaceDependency).length === 0 ); if (leafDependencies.length === 0) { - throw new Error('Circular dependency detected!'); + throw new Error("Circular dependency detected!"); } - leafDependencies.forEach(next => { + leafDependencies.forEach((next) => { ordered.push(next); delete remaining[next.name]; }); @@ -227,17 +227,17 @@ export class CratesTarget extends BaseTarget { const metadata = await this.getCrateMetadata(directory); const unorderedCrates = metadata.packages // only publish workspace members - .filter(p => metadata.workspace_members.indexOf(p.id) > -1) + .filter((p) => metadata.workspace_members.indexOf(p.id) > -1) // skip crates with `"publish": []` - .filter(p => !p.publish || p.publish.length); + .filter((p) => !p.publish || p.publish.length); const crates = this.getPublishOrder(unorderedCrates); logger.debug( `Publishing packages in the following order: ${crates - .map(c => c.name) - .join(', ')}` + .map((c) => c.name) + .join(", ")}` ); - return forEachChained(crates, async crate => this.publishPackage(crate)); + return forEachChained(crates, async (crate) => this.publishPackage(crate)); } /** @@ -248,12 +248,12 @@ export class CratesTarget extends BaseTarget { */ public async publishPackage(crate: CratePackage): Promise { const args = this.cratesConfig.noDevDeps - ? ['hack', 'publish', '--allow-dirty', '--no-dev-deps'] - : ['publish']; + ? ["hack", "publish", "--allow-dirty", "--no-dev-deps"] + : ["publish"]; args.push( - '--no-verify', // Verification should be done on the CI stage - '--manifest-path', + "--no-verify", // Verification should be done on the CI stage + "--manifest-path", crate.manifest_path ); @@ -300,12 +300,12 @@ export class CratesTarget extends BaseTarget { await git.checkout(revision); logger.info(`Checking out submodules`); - await git.submoduleUpdate(['--init']); + await git.submoduleUpdate(["--init"]); // Cargo seems to run into problems if the crate resides within a git // checkout located in a memory file system on Mac (e.g. /tmp). This can be // avoided by signaling to cargo that this is not a git checkout. - const gitdir = path.join(directory, '.git'); + const gitdir = path.join(directory, ".git"); fs.renameSync(gitdir, `${gitdir}.bak`); } @@ -321,14 +321,14 @@ export class CratesTarget extends BaseTarget { public async publish(_version: string, revision: string): Promise { const githubConfig = getGlobalGithubConfig(); await withTempDir( - async directory => { + async (directory) => { await this.cloneWithSubmodules(githubConfig, revision, directory); await this.publishWorkspace(directory); }, true, - 'craft-crates-' + "craft-crates-" ); - logger.info('Crates release complete'); + logger.info("Crates release complete"); } } diff --git a/src/targets/docker.ts b/src/targets/docker.ts index 4aee6535..9f671665 100644 --- a/src/targets/docker.ts +++ b/src/targets/docker.ts @@ -1,14 +1,14 @@ -import { logger as loggerRaw } from '../logger'; -import { TargetConfig } from '../schemas/project_config'; -import { BaseArtifactProvider } from '../artifact_providers/base'; -import { ConfigurationError } from '../utils/errors'; -import { renderTemplateSafe } from '../utils/strings'; -import { checkExecutableIsPresent, spawnProcess } from '../utils/system'; -import { BaseTarget } from './base'; +import { logger as loggerRaw } from "../logger"; +import { TargetConfig } from "../schemas/project_config"; +import { BaseArtifactProvider } from "../artifact_providers/base"; +import { ConfigurationError } from "../utils/errors"; +import { renderTemplateSafe } from "../utils/strings"; +import { checkExecutableIsPresent, spawnProcess } from "../utils/system"; +import { BaseTarget } from "./base"; -const logger = loggerRaw.withScope('[docker]'); +const logger = loggerRaw.withScope("[docker]"); -const DEFAULT_DOCKER_BIN = 'docker'; +const DEFAULT_DOCKER_BIN = "docker"; /** * Command to launch docker @@ -34,7 +34,7 @@ export interface DockerTargetOptions { */ export class DockerTarget extends BaseTarget { /** Target name */ - public readonly name: string = 'docker'; + public readonly name: string = "docker"; /** Target options */ public readonly dockerConfig: DockerTargetOptions; @@ -56,7 +56,7 @@ export class DockerTarget extends BaseTarget { `Cannot perform Docker release: missing credentials. Please use DOCKER_USERNAME and DOCKER_PASSWORD environment variables.`.replace( /^\s+/gm, - '' + "" ) ); } @@ -65,8 +65,8 @@ export class DockerTarget extends BaseTarget { password: process.env.DOCKER_PASSWORD, source: this.config.source, target: this.config.target, - sourceTemplate: this.config.sourceFormat || '{{{source}}}:{{{revision}}}', - targetTemplate: this.config.targetFormat || '{{{target}}}:{{{version}}}', + sourceTemplate: this.config.sourceFormat || "{{{source}}}:{{{revision}}}", + targetTemplate: this.config.targetFormat || "{{{target}}}:{{{version}}}", username: process.env.DOCKER_USERNAME, }; } @@ -79,7 +79,7 @@ export class DockerTarget extends BaseTarget { public async login(): Promise { const { username, password } = this.dockerConfig; return spawnProcess(DOCKER_BIN, [ - 'login', + "login", `--username=${username}`, `--password=${password}`, ]); @@ -90,14 +90,14 @@ export class DockerTarget extends BaseTarget { * @param revision Image tag, usually the git revision */ public async pull(revision: string): Promise { - logger.debug('Pulling source image...'); + logger.debug("Pulling source image..."); const sourceImage = renderTemplateSafe(this.dockerConfig.sourceTemplate, { ...this.dockerConfig, revision, }); return spawnProcess( DOCKER_BIN, - ['pull', sourceImage], + ["pull", sourceImage], {}, { enableInDryRunMode: true } ); @@ -117,11 +117,11 @@ export class DockerTarget extends BaseTarget { ...this.dockerConfig, version, }); - logger.debug('Tagging target image...'); - await spawnProcess(DOCKER_BIN, ['tag', sourceImage, targetImage]); + logger.debug("Tagging target image..."); + await spawnProcess(DOCKER_BIN, ["tag", sourceImage, targetImage]); return spawnProcess( DOCKER_BIN, - ['push', targetImage], + ["push", targetImage], {}, { showStdout: true } ); @@ -138,6 +138,6 @@ export class DockerTarget extends BaseTarget { await this.pull(revision); await this.push(revision, version); - logger.info('Docker release complete'); + logger.info("Docker release complete"); } } diff --git a/src/targets/gcs.ts b/src/targets/gcs.ts index 0c2ea2bd..ded86b88 100644 --- a/src/targets/gcs.ts +++ b/src/targets/gcs.ts @@ -1,20 +1,20 @@ -import { logger as loggerRaw } from '../logger'; -import { TargetConfig } from '../schemas/project_config'; -import { forEachChained } from '../utils/async'; -import { ConfigurationError, reportError } from '../utils/errors'; +import { logger as loggerRaw } from "../logger"; +import { TargetConfig } from "../schemas/project_config"; +import { forEachChained } from "../utils/async"; +import { ConfigurationError, reportError } from "../utils/errors"; import { BucketPath, CraftGCSClient, GCSBucketConfig, getGCSCredsFromEnv, DEFAULT_UPLOAD_METADATA, -} from '../utils/gcsApi'; -import { renderTemplateSafe } from '../utils/strings'; -import { BaseTarget } from './base'; +} from "../utils/gcsApi"; +import { renderTemplateSafe } from "../utils/strings"; +import { BaseTarget } from "./base"; import { BaseArtifactProvider, RemoteArtifact, -} from '../artifact_providers/base'; +} from "../artifact_providers/base"; const logger = loggerRaw.withScope(`[gcs]`); @@ -23,7 +23,7 @@ const logger = loggerRaw.withScope(`[gcs]`); * * Omits required property `path` since that will be computed dynamically later. */ -interface PathTemplate extends Omit { +interface PathTemplate extends Omit { /** * Template for the path, into which `version` and `revision` can be * substituted @@ -44,7 +44,7 @@ export interface GCSTargetConfig extends GCSBucketConfig { */ export class GcsTarget extends BaseTarget { /** Target name */ - public readonly name: string = 'gcs'; + public readonly name: string = "gcs"; /** Target options */ public readonly targetConfig: GCSTargetConfig; /** GCS API client */ @@ -65,12 +65,12 @@ export class GcsTarget extends BaseTarget { protected getGCSTargetConfig(): GCSTargetConfig { const { project_id, client_email, private_key } = getGCSCredsFromEnv( { - name: 'CRAFT_GCS_TARGET_CREDS_JSON', - legacyName: 'CRAFT_GCS_CREDENTIALS_JSON', + name: "CRAFT_GCS_TARGET_CREDS_JSON", + legacyName: "CRAFT_GCS_CREDENTIALS_JSON", }, { - name: 'CRAFT_GCS_TARGET_CREDS_PATH', - legacyName: 'CRAFT_GCS_CREDENTIALS_PATH', + name: "CRAFT_GCS_TARGET_CREDS_PATH", + legacyName: "CRAFT_GCS_CREDENTIALS_PATH", }, logger ); @@ -78,7 +78,7 @@ export class GcsTarget extends BaseTarget { const bucketName = this.config.bucket; // TODO (kmclb) get rid of this check once config validation is working if (!bucketName) { - reportError('No GCS bucket provided!'); + reportError("No GCS bucket provided!"); } const pathTemplates: PathTemplate[] = this.parseRawPathConfig( @@ -111,12 +111,12 @@ export class GcsTarget extends BaseTarget { // in JS empty arrays are truthy (rawPathConfig.length && rawPathConfig.length === 0) ) { - reportError('No bucket paths provided!'); + reportError("No bucket paths provided!"); } // if there's only one path, and no metadata specified, path config can be // provided as a string rather than an array of objects - else if (typeof rawPathConfig === 'string') { + else if (typeof rawPathConfig === "string") { parsedTemplates = [ { template: rawPathConfig, @@ -129,7 +129,7 @@ export class GcsTarget extends BaseTarget { // and `metadata` else if (Array.isArray(rawPathConfig)) { rawPathConfig.forEach((configEntry: any) => { - if (typeof configEntry !== 'object') { + if (typeof configEntry !== "object") { reportError( `Invalid bucket destination: ${JSON.stringify( configEntry @@ -142,7 +142,7 @@ export class GcsTarget extends BaseTarget { if (!template) { reportError(`Invalid bucket path template: ${template}`); } - if (metadata && typeof metadata !== 'object') { + if (metadata && typeof metadata !== "object") { reportError( `Invalid metadata for path "${template}": "${JSON.stringify( metadata @@ -191,7 +191,7 @@ export class GcsTarget extends BaseTarget { }); // enforce the constraint that all paths must start with a slash - if (realPath[0] !== '/') { + if (realPath[0] !== "/") { realPath = `/${realPath}`; } logger.debug( @@ -213,7 +213,7 @@ export class GcsTarget extends BaseTarget { const artifacts = await this.getArtifactsForRevision(revision); if (!artifacts.length) { throw new ConfigurationError( - 'No artifacts to publish: please check your configuration!' + "No artifacts to publish: please check your configuration!" ); } @@ -251,13 +251,13 @@ export class GcsTarget extends BaseTarget { ); return Promise.all( - localFilePaths.map(async localPath => + localFilePaths.map(async (localPath) => this.gcsClient.uploadArtifact(localPath, bucketPath) ) ); } ); - logger.info('Upload to GCS complete.'); + logger.info("Upload to GCS complete."); } } diff --git a/src/targets/gem.ts b/src/targets/gem.ts index 7ed6bcb9..2bb37507 100644 --- a/src/targets/gem.ts +++ b/src/targets/gem.ts @@ -1,16 +1,16 @@ -import { logger as loggerRaw } from '../logger'; +import { logger as loggerRaw } from "../logger"; import { BaseArtifactProvider, RemoteArtifact, -} from '../artifact_providers/base'; -import { reportError } from '../utils/errors'; -import { checkExecutableIsPresent, spawnProcess } from '../utils/system'; -import { BaseTarget } from './base'; -import { TargetConfig } from 'src/schemas/project_config'; +} from "../artifact_providers/base"; +import { reportError } from "../utils/errors"; +import { checkExecutableIsPresent, spawnProcess } from "../utils/system"; +import { BaseTarget } from "./base"; +import { TargetConfig } from "src/schemas/project_config"; -const logger = loggerRaw.withScope('[gem]'); +const logger = loggerRaw.withScope("[gem]"); -const DEFAULT_GEM_BIN = 'gem'; +const DEFAULT_GEM_BIN = "gem"; /** * Command to launch gem @@ -27,7 +27,7 @@ const DEFAULT_GEM_REGEX = /^.*(\.gem)$/; */ export class GemTarget extends BaseTarget { /** Target name */ - public readonly name: string = 'gem'; + public readonly name: string = "gem"; public constructor( config: TargetConfig, @@ -44,7 +44,7 @@ export class GemTarget extends BaseTarget { * @returns A promise that resolves when the gem pushed */ public async pushGem(path: string): Promise { - return spawnProcess(GEM_BIN, ['push', path]); + return spawnProcess(GEM_BIN, ["push", path]); } /** @@ -54,13 +54,13 @@ export class GemTarget extends BaseTarget { * @param revision Git commit SHA to be published */ public async publish(_version: string, revision: string): Promise { - logger.debug('Fetching artifact list...'); + logger.debug("Fetching artifact list..."); const packageFiles = await this.getArtifactsForRevision(revision, { includeNames: DEFAULT_GEM_REGEX, }); if (!packageFiles.length) { - reportError('Cannot push gem: no packages found'); + reportError("Cannot push gem: no packages found"); return undefined; } @@ -72,6 +72,6 @@ export class GemTarget extends BaseTarget { }) ); - logger.info('Successfully registered gem'); + logger.info("Successfully registered gem"); } } diff --git a/src/targets/ghPages.ts b/src/targets/ghPages.ts index 479f6f44..c36525c6 100644 --- a/src/targets/ghPages.ts +++ b/src/targets/ghPages.ts @@ -1,33 +1,33 @@ -import * as fs from 'fs'; -import * as path from 'path'; +import * as fs from "fs"; +import * as path from "path"; -import * as Github from '@octokit/rest'; -import simpleGit from 'simple-git'; +import * as Github from "@octokit/rest"; +import simpleGit from "simple-git"; -import { getGlobalGithubConfig } from '../config'; -import { logger as loggerRaw } from '../logger'; -import { GithubGlobalConfig, TargetConfig } from '../schemas/project_config'; -import { ConfigurationError, reportError } from '../utils/errors'; -import { withTempDir } from '../utils/files'; +import { getGlobalGithubConfig } from "../config"; +import { logger as loggerRaw } from "../logger"; +import { GithubGlobalConfig, TargetConfig } from "../schemas/project_config"; +import { ConfigurationError, reportError } from "../utils/errors"; +import { withTempDir } from "../utils/files"; import { getAuthUsername, getGithubApiToken, getGithubClient, GithubRemote, -} from '../utils/githubApi'; -import { isDryRun } from '../utils/helpers'; -import { extractZipArchive } from '../utils/system'; -import { BaseTarget } from './base'; -import { BaseArtifactProvider } from '../artifact_providers/base'; +} from "../utils/githubApi"; +import { isDryRun } from "../utils/helpers"; +import { extractZipArchive } from "../utils/system"; +import { BaseTarget } from "./base"; +import { BaseArtifactProvider } from "../artifact_providers/base"; -const logger = loggerRaw.withScope('[gh-pages]'); +const logger = loggerRaw.withScope("[gh-pages]"); /** * Regex for docs archives */ const DEFAULT_DEPLOY_ARCHIVE_REGEX = /^(?:.+-)?gh-pages\.zip$/; -const DEFAULT_DEPLOY_BRANCH = 'gh-pages'; +const DEFAULT_DEPLOY_BRANCH = "gh-pages"; /** Target options for "gh-pages" */ export interface GhPagesConfig { @@ -44,7 +44,7 @@ export interface GhPagesConfig { */ export class GhPagesTarget extends BaseTarget { /** Target name */ - public readonly name: string = 'gh-pages'; + public readonly name: string = "gh-pages"; /** Target options */ public readonly ghPagesConfig: GhPagesConfig; /** Github client */ @@ -76,7 +76,7 @@ export class GhPagesTarget extends BaseTarget { githubRepo = this.githubRepo.repo; } else { throw new ConfigurationError( - '[gh-pages] Invalid repository configuration: check repo owner and name' + "[gh-pages] Invalid repository configuration: check repo owner and name" ); } @@ -105,10 +105,10 @@ export class GhPagesTarget extends BaseTarget { directory: string ): Promise { // Check that the directory is empty - const dirContents = fs.readdirSync(directory).filter(f => f !== '.git'); + const dirContents = fs.readdirSync(directory).filter((f) => f !== ".git"); if (dirContents.length > 0) { throw new Error( - 'Destination directory is not empty: cannot extract the acrhive!' + "Destination directory is not empty: cannot extract the acrhive!" ); } @@ -117,14 +117,16 @@ export class GhPagesTarget extends BaseTarget { await extractZipArchive(archivePath, directory); // If there's a single top-level directory -- move its contents to the git root - const newDirContents = fs.readdirSync(directory).filter(f => f !== '.git'); + const newDirContents = fs + .readdirSync(directory) + .filter((f) => f !== ".git"); if ( newDirContents.length === 1 && fs.statSync(path.join(directory, newDirContents[0])).isDirectory() ) { - logger.debug('Single top-level directory found, moving files from it...'); + logger.debug("Single top-level directory found, moving files from it..."); const innerDirPath = path.join(directory, newDirContents[0]); - fs.readdirSync(innerDirPath).forEach(item => { + fs.readdirSync(innerDirPath).forEach((item) => { const srcPath = path.join(innerDirPath, item); const destPath = path.join(directory, item); fs.renameSync(srcPath, destPath); @@ -162,12 +164,12 @@ export class GhPagesTarget extends BaseTarget { logger.debug( `Branch ${branch} does not exist, creating a new orphaned branch...` ); - await git.checkout(['--orphan', branch]); + await git.checkout(["--orphan", branch]); } // Additional check, just in case const repoStatus = await git.status(); - if (repoStatus.current !== 'No' && repoStatus.current !== branch) { + if (repoStatus.current !== "No" && repoStatus.current !== branch) { throw new Error( `Something went very wrong: cannot switch to branch "${branch}"` ); @@ -175,21 +177,21 @@ export class GhPagesTarget extends BaseTarget { // Clean the previous state logger.debug(`Removing existing files from the working tree...`); - await git.rm(['-r', '-f', '.']); + await git.rm(["-r", "-f", "."]); // Extract the archive await this.extractAssets(archivePath, directory); // Commit - await git.add(['.']); + await git.add(["."]); await git.commit(`craft(gh-pages): update, version "${version}"`); // Push! logger.info(`Pushing branch "${branch}"...`); if (!isDryRun()) { - await git.push('origin', branch, ['--set-upstream']); + await git.push("origin", branch, ["--set-upstream"]); } else { - logger.info('[dry-run] Not pushing the branch.'); + logger.info("[dry-run] Not pushing the branch."); } } @@ -199,12 +201,12 @@ export class GhPagesTarget extends BaseTarget { public async publish(version: string, revision: string): Promise { const { githubOwner, githubRepo, branch } = this.ghPagesConfig; - logger.debug('Fetching artifact list...'); + logger.debug("Fetching artifact list..."); const packageFiles = await this.getArtifactsForRevision(revision, { includeNames: DEFAULT_DEPLOY_ARCHIVE_REGEX, }); if (!packageFiles.length) { - reportError('Cannot release to GH-pages: no artifacts found'); + reportError("Cannot release to GH-pages: no artifacts found"); return undefined; } else if (packageFiles.length > 1) { reportError( @@ -228,7 +230,7 @@ export class GhPagesTarget extends BaseTarget { ); await withTempDir( - async directory => + async (directory) => this.commitArchiveToBranch( directory, remote, @@ -237,9 +239,9 @@ export class GhPagesTarget extends BaseTarget { version ), true, - 'craft-gh-pages-' + "craft-gh-pages-" ); - logger.info('GitHub pages release complete'); + logger.info("GitHub pages release complete"); } } diff --git a/src/targets/github.ts b/src/targets/github.ts index 713bd6c9..fdd9d29e 100644 --- a/src/targets/github.ts +++ b/src/targets/github.ts @@ -1,29 +1,29 @@ -import * as Github from '@octokit/rest'; -import { createReadStream, statSync } from 'fs'; -import { basename } from 'path'; +import * as Github from "@octokit/rest"; +import { createReadStream, statSync } from "fs"; +import { basename } from "path"; -import { getConfiguration, getGlobalGithubConfig } from '../config'; -import { logger as loggerRaw } from '../logger'; -import { GithubGlobalConfig, TargetConfig } from '../schemas/project_config'; -import { DEFAULT_CHANGELOG_PATH, findChangeset } from '../utils/changes'; +import { getConfiguration, getGlobalGithubConfig } from "../config"; +import { logger as loggerRaw } from "../logger"; +import { GithubGlobalConfig, TargetConfig } from "../schemas/project_config"; +import { DEFAULT_CHANGELOG_PATH, findChangeset } from "../utils/changes"; import { getFile, getGithubClient, HTTP_RESPONSE_5XX, HTTP_UNPROCESSABLE_ENTITY, retryHttp, -} from '../utils/githubApi'; -import { isDryRun } from '../utils/helpers'; -import { isPreviewRelease, versionToTag } from '../utils/version'; -import { BaseTarget } from './base'; -import { BaseArtifactProvider } from '../artifact_providers/base'; +} from "../utils/githubApi"; +import { isDryRun } from "../utils/helpers"; +import { isPreviewRelease, versionToTag } from "../utils/version"; +import { BaseTarget } from "./base"; +import { BaseArtifactProvider } from "../artifact_providers/base"; -const logger = loggerRaw.withScope('[github]'); +const logger = loggerRaw.withScope("[github]"); /** * Default content type for GitHub release assets */ -export const DEFAULT_CONTENT_TYPE = 'application/octet-stream'; +export const DEFAULT_CONTENT_TYPE = "application/octet-stream"; /** * Configuration options for the Github target @@ -55,14 +55,14 @@ interface GithubRelease { /** * Tag type as used in GitdataCreateTagParams from Github API */ -type GithubCreateTagType = 'commit' | 'tree' | 'blob'; +type GithubCreateTagType = "commit" | "tree" | "blob"; /** * Target responsible for publishing releases on Github */ export class GithubTarget extends BaseTarget { /** Target name */ - public readonly name: string = 'github'; + public readonly name: string = "github"; /** Target options */ public readonly githubConfig: GithubTargetConfig; /** Github client */ @@ -77,11 +77,11 @@ export class GithubTarget extends BaseTarget { ...getGlobalGithubConfig(), annotatedTag: this.config.annotatedTag === undefined || !!this.config.annotatedTag, - changelog: getConfiguration().changelog || '', + changelog: getConfiguration().changelog || "", previewReleases: this.config.previewReleases === undefined || !!this.config.previewReleases, - tagPrefix: this.config.tagPrefix || '', + tagPrefix: this.config.tagPrefix || "", }; this.github = getGithubClient(); } @@ -110,7 +110,7 @@ export class GithubTarget extends BaseTarget { owner: this.githubConfig.owner, repo: this.githubConfig.repo, tag, - type: 'commit' as GithubCreateTagType, + type: "commit" as GithubCreateTagType, }; const tagCreatedResponse = await this.github.git.createTag(createTagParams); @@ -178,7 +178,7 @@ export class GithubTarget extends BaseTarget { revision ); const changes = (changelog && findChangeset(changelog, tag)) || {}; - logger.debug('Changes extracted from changelog: ', JSON.stringify(changes)); + logger.debug("Changes extracted from changelog: ", JSON.stringify(changes)); const createReleaseParams = { draft: false, @@ -196,12 +196,12 @@ export class GithubTarget extends BaseTarget { if (this.githubConfig.annotatedTag) { await this.createAnnotatedTag(version, revision, tag); // We've just created the tag, so "target_commitish" will not be used. - createReleaseParams.target_commitish = ''; + createReleaseParams.target_commitish = ""; } logger.info( `Creating a new ${ - isPreview ? '*preview* ' : '' + isPreview ? "*preview* " : "" }release for tag "${tag}"` ); const created = await this.github.repos.createRelease( @@ -213,7 +213,7 @@ export class GithubTarget extends BaseTarget { return { id: 0, tag_name: tag, - upload_url: '', + upload_url: "", }; } } @@ -312,18 +312,18 @@ export class GithubTarget extends BaseTarget { const stats = statSync(path); const name = basename(path); const params = { - 'Content-Length': stats.size, - 'Content-Type': contentTypeProcessed, + "Content-Length": stats.size, + "Content-Type": contentTypeProcessed, file: createReadStream(path), headers: { - 'content-length': stats.size, - 'content-type': contentTypeProcessed, + "content-length": stats.size, + "content-type": contentTypeProcessed, }, id: release.id, name, url: release.upload_url, }; - logger.debug('Upload parameters:', JSON.stringify(params)); + logger.debug("Upload parameters:", JSON.stringify(params)); logger.info( `Uploading asset "${name}" to ${this.githubConfig.owner}/${this.githubConfig.repo}:${release.tag_name}` ); @@ -333,7 +333,7 @@ export class GithubTarget extends BaseTarget { async () => this.github.repos.uploadReleaseAsset(params), { cleanupFn: async () => { - logger.debug('Cleaning up before the next retry...'); + logger.debug("Cleaning up before the next retry..."); return this.deleteAssetsByFilename(release, name); }, retries: 5, @@ -370,7 +370,7 @@ export class GithubTarget extends BaseTarget { } else { const assets = await this.getAssetsForRelease(release); if (assets.length > 0) { - logger.warn('Existing assets found for the release, deleting them...'); + logger.warn("Existing assets found for the release, deleting them..."); await this.deleteAssets(assets); logger.debug(`Deleted ${assets.length} assets`); } @@ -378,7 +378,7 @@ export class GithubTarget extends BaseTarget { const artifacts = await this.getArtifactsForRevision(revision); await Promise.all( - artifacts.map(async artifact => { + artifacts.map(async (artifact) => { const path = await this.artifactProvider.downloadArtifact(artifact); return this.uploadAsset(release, path, artifact.mimeType); }) diff --git a/src/targets/index.ts b/src/targets/index.ts index 8fb44f85..769caac0 100644 --- a/src/targets/index.ts +++ b/src/targets/index.ts @@ -1,18 +1,18 @@ -import { TargetConfig } from 'src/schemas/project_config'; -import { BaseTarget } from './base'; -import { BrewTarget } from './brew'; -import { CocoapodsTarget } from './cocoapods'; -import { CratesTarget } from './crates'; -import { DockerTarget } from './docker'; -import { GcsTarget } from './gcs'; -import { GemTarget } from './gem'; -import { GhPagesTarget } from './ghPages'; -import { GithubTarget } from './github'; -import { NpmTarget } from './npm'; -import { NugetTarget } from './nuget'; -import { PypiTarget } from './pypi'; -import { RegistryTarget } from './registry'; -import { AwsLambdaLayerTarget } from './awsLambdaLayer'; +import { TargetConfig } from "src/schemas/project_config"; +import { BaseTarget } from "./base"; +import { BrewTarget } from "./brew"; +import { CocoapodsTarget } from "./cocoapods"; +import { CratesTarget } from "./crates"; +import { DockerTarget } from "./docker"; +import { GcsTarget } from "./gcs"; +import { GemTarget } from "./gem"; +import { GhPagesTarget } from "./ghPages"; +import { GithubTarget } from "./github"; +import { NpmTarget } from "./npm"; +import { NugetTarget } from "./nuget"; +import { PypiTarget } from "./pypi"; +import { RegistryTarget } from "./registry"; +import { AwsLambdaLayerTarget } from "./awsLambdaLayer"; export const TARGET_MAP: { [key: string]: typeof BaseTarget } = { brew: BrewTarget, @@ -21,21 +21,21 @@ export const TARGET_MAP: { [key: string]: typeof BaseTarget } = { docker: DockerTarget, gcs: GcsTarget, gem: GemTarget, - 'gh-pages': GhPagesTarget, + "gh-pages": GhPagesTarget, github: GithubTarget, npm: NpmTarget, nuget: NugetTarget, pypi: PypiTarget, registry: RegistryTarget, - 'aws-lambda-layer': AwsLambdaLayerTarget, + "aws-lambda-layer": AwsLambdaLayerTarget, }; /** Targets that are treated specially */ export enum SpecialTarget { /** This targets does not do any publishing, only related workflow actions (e.g. merging the release branch) */ - None = 'none', + None = "none", /** This target is an alias for running all configured targets */ - All = 'all', + All = "all", } /** @@ -62,5 +62,5 @@ export function getTargetByName( export function getTargetId(target: TargetConfig): string { return target.id ? `${target.name}[${target.id}]` - : target.name || '__undefined__'; + : target.name || "__undefined__"; } diff --git a/src/targets/npm.ts b/src/targets/npm.ts index 7bf3755d..0f1437e7 100644 --- a/src/targets/npm.ts +++ b/src/targets/npm.ts @@ -1,32 +1,32 @@ -import { SpawnOptions, spawnSync } from 'child_process'; -import * as inquirer from 'inquirer'; - -import { logger as loggerRaw } from '../logger'; -import { TargetConfig } from '../schemas/project_config'; -import { ConfigurationError, reportError } from '../utils/errors'; -import { isDryRun } from '../utils/helpers'; -import { hasExecutable, spawnProcess } from '../utils/system'; -import { isPreviewRelease, parseVersion } from '../utils/version'; -import { BaseTarget } from './base'; +import { SpawnOptions, spawnSync } from "child_process"; +import * as inquirer from "inquirer"; + +import { logger as loggerRaw } from "../logger"; +import { TargetConfig } from "../schemas/project_config"; +import { ConfigurationError, reportError } from "../utils/errors"; +import { isDryRun } from "../utils/helpers"; +import { hasExecutable, spawnProcess } from "../utils/system"; +import { isPreviewRelease, parseVersion } from "../utils/version"; +import { BaseTarget } from "./base"; import { BaseArtifactProvider, RemoteArtifact, -} from '../artifact_providers/base'; -import { withTempFile } from '../utils/files'; -import { writeFileSync } from 'fs'; +} from "../artifact_providers/base"; +import { withTempFile } from "../utils/files"; +import { writeFileSync } from "fs"; -const logger = loggerRaw.withScope('[npm]'); +const logger = loggerRaw.withScope("[npm]"); /** Command to launch "npm" */ -export const NPM_BIN = process.env.NPM_BIN || 'npm'; +export const NPM_BIN = process.env.NPM_BIN || "npm"; /** Command to launch "yarn" */ -export const YARN_BIN = process.env.YARN_BIN || 'yarn'; +export const YARN_BIN = process.env.YARN_BIN || "yarn"; const NPM_MIN_MAJOR = 5; const NPM_MIN_MINOR = 6; -const NPM_TOKEN_ENV_VAR = 'NPM_TOKEN'; +const NPM_TOKEN_ENV_VAR = "NPM_TOKEN"; /** A regular expression used to find the package tarball */ const DEFAULT_PACKAGE_REGEX = /^.*\d\.\d.*\.tgz$/; @@ -34,9 +34,9 @@ const DEFAULT_PACKAGE_REGEX = /^.*\d\.\d.*\.tgz$/; /** Access specifiers for NPM packages. See npm-publish doc for more info */ export enum NpmPackageAccess { /** Public access: anyone can see the package */ - PUBLIC = 'public', + PUBLIC = "public", /** Restricted access: scoped packages are restricted by default, for example */ - RESTRICTED = 'restricted', + RESTRICTED = "restricted", } /** NPM target configuration options */ @@ -64,7 +64,7 @@ interface NpmPublishOptions { */ export class NpmTarget extends BaseTarget { /** Target name */ - public readonly name: string = 'npm'; + public readonly name: string = "npm"; /** Target options */ public readonly npmConfig: NpmTargetOptions; @@ -82,8 +82,8 @@ export class NpmTarget extends BaseTarget { */ protected checkRequirements(): void { if (hasExecutable(NPM_BIN)) { - logger.debug('Checking that NPM has recent version...'); - const npmVersion = spawnSync(NPM_BIN, ['--version']) + logger.debug("Checking that NPM has recent version..."); + const npmVersion = spawnSync(NPM_BIN, ["--version"]) .stdout.toString() .trim(); const parsedVersion = parseVersion(npmVersion); @@ -101,7 +101,7 @@ export class NpmTarget extends BaseTarget { } logger.debug(`Found NPM version ${npmVersion}`); } else if (hasExecutable(YARN_BIN)) { - const yarnVersion = spawnSync(YARN_BIN, ['--version']) + const yarnVersion = spawnSync(YARN_BIN, ["--version"]) .stdout.toString() .trim(); logger.debug(`Found Yarn version ${yarnVersion}`); @@ -116,11 +116,11 @@ export class NpmTarget extends BaseTarget { protected async requestOtp(): Promise { const questions = [ { - message: 'Looks like your NPM account uses 2FA. Enter OTP:', - name: 'otp', - type: 'input', + message: "Looks like your NPM account uses 2FA. Enter OTP:", + name: "otp", + type: "input", validate: (input: string) => - (input.length > 3 && input.length < 10) || 'Valid OTP, please', + (input.length > 3 && input.length < 10) || "Valid OTP, please", }, ]; const answers = (await inquirer.prompt(questions)) as any; @@ -133,7 +133,7 @@ export class NpmTarget extends BaseTarget { protected getNpmConfig(): NpmTargetOptions { const token = process.env.NPM_TOKEN; if (!token) { - throw new Error('NPM target: NPM_TOKEN not found in the environment'); + throw new Error("NPM target: NPM_TOKEN not found in the environment"); } const npmConfig: NpmTargetOptions = { @@ -150,8 +150,8 @@ export class NpmTarget extends BaseTarget { } } - const useOtp = (process.env.CRAFT_NPM_USE_OTP || '').toLowerCase(); - if (['1', 'true', 'yes'].indexOf(useOtp) > -1) { + const useOtp = (process.env.CRAFT_NPM_USE_OTP || "").toLowerCase(); + if (["1", "true", "yes"].indexOf(useOtp) > -1) { npmConfig.useOtp = true; } return npmConfig; @@ -167,13 +167,13 @@ export class NpmTarget extends BaseTarget { path: string, options: NpmPublishOptions ): Promise { - const args = ['publish']; + const args = ["publish"]; let bin: string; if (this.npmConfig.useYarn) { bin = YARN_BIN; args.push(`--new-version=${options.version}`); - args.push('--non-interactive'); + args.push("--non-interactive"); } else { bin = NPM_BIN; } @@ -187,12 +187,12 @@ export class NpmTarget extends BaseTarget { // In case we have a prerelease, there should never be a reason to publish // it with the latest tag in npm. if (isPreviewRelease(options.version)) { - logger.warn('Detected pre-release version for npm package!'); + logger.warn("Detected pre-release version for npm package!"); logger.warn('Adding tag "next" to not make it "latest" in registry.'); - args.push('--tag=next'); + args.push("--tag=next"); } - return withTempFile(filePath => { + return withTempFile((filePath) => { // Pass OTP if configured const spawnOptions: SpawnOptions = {}; spawnOptions.env = { ...process.env }; @@ -224,13 +224,13 @@ export class NpmTarget extends BaseTarget { * @param revision Git commit SHA to be published */ public async publish(version: string, revision: string): Promise { - logger.debug('Fetching artifact list...'); + logger.debug("Fetching artifact list..."); const packageFiles = await this.getArtifactsForRevision(revision, { includeNames: DEFAULT_PACKAGE_REGEX, }); if (!packageFiles.length) { - reportError('Cannot release to NPM: no packages found!'); + reportError("Cannot release to NPM: no packages found!"); return undefined; } @@ -247,6 +247,6 @@ export class NpmTarget extends BaseTarget { }) ); - logger.info('NPM release complete'); + logger.info("NPM release complete"); } } diff --git a/src/targets/nuget.ts b/src/targets/nuget.ts index c109442f..6390352b 100644 --- a/src/targets/nuget.ts +++ b/src/targets/nuget.ts @@ -1,20 +1,20 @@ -import { logger as loggerRaw } from '../logger'; -import { TargetConfig } from '../schemas/project_config'; -import { ConfigurationError, reportError } from '../utils/errors'; -import { checkExecutableIsPresent, spawnProcess } from '../utils/system'; -import { BaseTarget } from './base'; +import { logger as loggerRaw } from "../logger"; +import { TargetConfig } from "../schemas/project_config"; +import { ConfigurationError, reportError } from "../utils/errors"; +import { checkExecutableIsPresent, spawnProcess } from "../utils/system"; +import { BaseTarget } from "./base"; import { BaseArtifactProvider, RemoteArtifact, -} from '../artifact_providers/base'; +} from "../artifact_providers/base"; -const logger = loggerRaw.withScope('[nuget]'); +const logger = loggerRaw.withScope("[nuget]"); /** Command to launch dotnet tools */ -export const NUGET_DOTNET_BIN = process.env.NUGET_DOTNET_BIN || 'dotnet'; +export const NUGET_DOTNET_BIN = process.env.NUGET_DOTNET_BIN || "dotnet"; /** Default Nuget registry URL */ -export const DEFAULT_NUGET_SERVER_URL = 'https://api.nuget.org/v3/index.json'; +export const DEFAULT_NUGET_SERVER_URL = "https://api.nuget.org/v3/index.json"; /** A regular expression used to find the package tarball */ const DEFAULT_NUGET_REGEX = /^.*\d\.\d.*\.nupkg$/; @@ -32,7 +32,7 @@ export interface NugetTargetOptions { */ export class NugetTarget extends BaseTarget { /** Target name */ - public readonly name: string = 'nuget'; + public readonly name: string = "nuget"; /** Target options */ public readonly nugetConfig: NugetTargetOptions; @@ -69,12 +69,12 @@ export class NugetTarget extends BaseTarget { */ public async uploadAsset(path: string): Promise { return spawnProcess(NUGET_DOTNET_BIN, [ - 'nuget', - 'push', + "nuget", + "push", path, - '--api-key', - '${NUGET_API_TOKEN}', - '--source', + "--api-key", + "${NUGET_API_TOKEN}", + "--source", this.nugetConfig.serverUrl, ]); } @@ -86,14 +86,14 @@ export class NugetTarget extends BaseTarget { * @param revision Git commit SHA to be published */ public async publish(_version: string, revision: string): Promise { - logger.debug('Fetching artifact list...'); + logger.debug("Fetching artifact list..."); const packageFiles = await this.getArtifactsForRevision(revision, { includeNames: DEFAULT_NUGET_REGEX, }); if (!packageFiles.length) { reportError( - 'Cannot release to Nuget: there are no Nuget packages found!' + "Cannot release to Nuget: there are no Nuget packages found!" ); } @@ -105,6 +105,6 @@ export class NugetTarget extends BaseTarget { }) ); - logger.info('Nuget release complete'); + logger.info("Nuget release complete"); } } diff --git a/src/targets/pypi.ts b/src/targets/pypi.ts index 18ee675d..eec04183 100644 --- a/src/targets/pypi.ts +++ b/src/targets/pypi.ts @@ -1,16 +1,16 @@ -import { logger as loggerRaw } from '../logger'; -import { TargetConfig } from '../schemas/project_config'; +import { logger as loggerRaw } from "../logger"; +import { TargetConfig } from "../schemas/project_config"; import { BaseArtifactProvider, RemoteArtifact, -} from '../artifact_providers/base'; -import { ConfigurationError, reportError } from '../utils/errors'; -import { checkExecutableIsPresent, spawnProcess } from '../utils/system'; -import { BaseTarget } from './base'; +} from "../artifact_providers/base"; +import { ConfigurationError, reportError } from "../utils/errors"; +import { checkExecutableIsPresent, spawnProcess } from "../utils/system"; +import { BaseTarget } from "./base"; -const logger = loggerRaw.withScope('[pypi]'); +const logger = loggerRaw.withScope("[pypi]"); -const DEFAULT_TWINE_BIN = 'twine'; +const DEFAULT_TWINE_BIN = "twine"; /** * Command to launch twine @@ -35,7 +35,7 @@ export interface PypiTargetOptions { */ export class PypiTarget extends BaseTarget { /** Target name */ - public readonly name: string = 'pypi'; + public readonly name: string = "pypi"; /** Target options */ public readonly pypiConfig: PypiTargetOptions; @@ -57,7 +57,7 @@ export class PypiTarget extends BaseTarget { `Cannot perform PyPI release: missing credentials. Please use TWINE_USERNAME and TWINE_PASSWORD environment variables.`.replace( /^\s+/gm, - '' + "" ) ); } @@ -75,7 +75,7 @@ export class PypiTarget extends BaseTarget { */ public async uploadAsset(path: string): Promise { // TODO: Sign the package with "--sign" - return spawnProcess(TWINE_BIN, ['upload', path]); + return spawnProcess(TWINE_BIN, ["upload", path]); } /** @@ -88,13 +88,13 @@ export class PypiTarget extends BaseTarget { * @param revision Git commit SHA to be published */ public async publish(_version: string, revision: string): Promise { - logger.debug('Fetching artifact list...'); + logger.debug("Fetching artifact list..."); const packageFiles = await this.getArtifactsForRevision(revision, { includeNames: DEFAULT_PYPI_REGEX, }); if (!packageFiles.length) { - reportError('Cannot release to PyPI: no packages found'); + reportError("Cannot release to PyPI: no packages found"); return undefined; } @@ -106,6 +106,6 @@ export class PypiTarget extends BaseTarget { }) ); - logger.info('PyPI release complete'); + logger.info("PyPI release complete"); } } diff --git a/src/targets/registry.ts b/src/targets/registry.ts index 20f4db92..d8b28c03 100644 --- a/src/targets/registry.ts +++ b/src/targets/registry.ts @@ -1,48 +1,48 @@ -import { mapLimit } from 'async'; -import * as Github from '@octokit/rest'; -import * as _ from 'lodash'; -import simpleGit from 'simple-git'; -import * as path from 'path'; - -import { getGlobalGithubConfig } from '../config'; -import { logger as loggerRaw } from '../logger'; -import { GithubGlobalConfig, TargetConfig } from '../schemas/project_config'; -import { ConfigurationError, reportError } from '../utils/errors'; -import { withTempDir } from '../utils/files'; +import { mapLimit } from "async"; +import * as Github from "@octokit/rest"; +import * as _ from "lodash"; +import simpleGit from "simple-git"; +import * as path from "path"; + +import { getGlobalGithubConfig } from "../config"; +import { logger as loggerRaw } from "../logger"; +import { GithubGlobalConfig, TargetConfig } from "../schemas/project_config"; +import { ConfigurationError, reportError } from "../utils/errors"; +import { withTempDir } from "../utils/files"; import { getAuthUsername, getGithubApiToken, getGithubClient, GithubRemote, -} from '../utils/githubApi'; -import { renderTemplateSafe } from '../utils/strings'; -import { isPreviewRelease } from '../utils/version'; -import { stringToRegexp } from '../utils/filters'; -import { BaseTarget } from './base'; +} from "../utils/githubApi"; +import { renderTemplateSafe } from "../utils/strings"; +import { isPreviewRelease } from "../utils/version"; +import { stringToRegexp } from "../utils/filters"; +import { BaseTarget } from "./base"; import { RemoteArtifact, BaseArtifactProvider, MAX_DOWNLOAD_CONCURRENCY, -} from '../artifact_providers/base'; +} from "../artifact_providers/base"; import { castChecksums, ChecksumEntry, getArtifactChecksums, -} from '../utils/checksum'; -import * as registryUtils from '../utils/registry'; -import { getPackageDirPath } from '../utils/packagePath'; -import { isDryRun } from '../utils/helpers'; +} from "../utils/checksum"; +import * as registryUtils from "../utils/registry"; +import { getPackageDirPath } from "../utils/packagePath"; +import { isDryRun } from "../utils/helpers"; -const logger = loggerRaw.withScope('[registry]'); +const logger = loggerRaw.withScope("[registry]"); const DEFAULT_REGISTRY_REMOTE: GithubRemote = registryUtils.getRegistryGithubRemote(); /** Type of the registry package */ export enum RegistryPackageType { /** App is a generic package type that doesn't belong to any specific registry */ - APP = 'app', + APP = "app", /** SDK is a package hosted in one of public registries (PyPI, NPM, etc.) */ - SDK = 'sdk', + SDK = "sdk", } /** "registry" target options */ @@ -68,7 +68,7 @@ export interface RegistryConfig { */ export class RegistryTarget extends BaseTarget { /** Target name */ - public readonly name: string = 'registry'; + public readonly name: string = "registry"; /** Target options */ public readonly registryConfig: RegistryConfig; /** Github client */ @@ -104,7 +104,7 @@ export class RegistryTarget extends BaseTarget { let urlTemplate; if (registryType === RegistryPackageType.APP) { urlTemplate = this.config.urlTemplate; - if (urlTemplate && typeof urlTemplate !== 'string') { + if (urlTemplate && typeof urlTemplate !== "string") { throw new ConfigurationError( `Invalid "urlTemplate" specified: ${urlTemplate}` ); @@ -114,18 +114,18 @@ export class RegistryTarget extends BaseTarget { const releaseConfig = this.config.config; if (!releaseConfig) { throw new ConfigurationError( - 'Cannot find configuration dictionary for release registry' + "Cannot find configuration dictionary for release registry" ); } const canonicalName = releaseConfig.canonical; if (!canonicalName) { throw new ConfigurationError( - 'Canonical name not found in the configuration' + "Canonical name not found in the configuration" ); } const linkPrereleases = this.config.linkPrereleases || false; - if (typeof linkPrereleases !== 'boolean') { + if (typeof linkPrereleases !== "boolean") { throw new ConfigurationError('Invlaid type of "linkPrereleases"'); } @@ -134,7 +134,7 @@ export class RegistryTarget extends BaseTarget { const onlyIfPresentStr = this.config.onlyIfPresent || undefined; let onlyIfPresent; if (onlyIfPresentStr) { - if (typeof onlyIfPresentStr !== 'string') { + if (typeof onlyIfPresentStr !== "string") { throw new ConfigurationError('Invalid type of "onlyIfPresent"'); } onlyIfPresent = stringToRegexp(onlyIfPresentStr); @@ -173,7 +173,7 @@ export class RegistryTarget extends BaseTarget { const artifacts = await this.getArtifactsForRevision(revision); if (artifacts.length === 0) { - logger.warn('No artifacts found, not adding any links to the manifest'); + logger.warn("No artifacts found, not adding any links to the manifest"); return; } @@ -259,16 +259,16 @@ export class RegistryTarget extends BaseTarget { const artifacts = await this.getArtifactsForRevision(revision); if (artifacts.length === 0) { - logger.warn('No artifacts found, not adding any file data'); + logger.warn("No artifacts found, not adding any file data"); return; } logger.info( - 'Adding extra data (checksums, download links) for available artifacts...' + "Adding extra data (checksums, download links) for available artifacts..." ); const files: { [key: string]: any } = {}; - await mapLimit(artifacts, MAX_DOWNLOAD_CONCURRENCY, async artifact => { + await mapLimit(artifacts, MAX_DOWNLOAD_CONCURRENCY, async (artifact) => { const fileData = await this.getArtifactData(artifact, version, revision); if (!_.isEmpty(fileData)) { files[artifact.filename] = fileData; @@ -342,8 +342,8 @@ export class RegistryTarget extends BaseTarget { const git = simpleGit(directory); logger.info(`Cloning "${remote.getRemoteString()}" to "${directory}"...`); await git.clone(remote.getRemoteStringWithAuth(), directory, [ - '--filter=tree:0', - '--single-branch', + "--filter=tree:0", + "--single-branch", ]); const packageDirPath = getPackageDirPath( @@ -370,18 +370,18 @@ export class RegistryTarget extends BaseTarget { ); // Commit - await git.add(['.']); + await git.add(["."]); await git.commit(`craft: release "${canonicalName}", version "${version}"`); // Ensure we are still up to date with upstream - await git.pull('origin', 'master', ['--rebase']); + await git.pull("origin", "master", ["--rebase"]); // Push! if (!isDryRun()) { logger.info(`Pushing the changes...`); - await git.push('origin', 'master'); + await git.push("origin", "master"); } else { - logger.info('[dry-run] Not pushing the changes.'); + logger.info("[dry-run] Not pushing the changes."); } } @@ -390,7 +390,7 @@ export class RegistryTarget extends BaseTarget { */ public async publish(version: string, revision: string): Promise { if (!this.registryConfig.linkPrereleases && isPreviewRelease(version)) { - logger.info('Preview release detected, skipping the target'); + logger.info("Preview release detected, skipping the target"); return undefined; } @@ -416,11 +416,11 @@ export class RegistryTarget extends BaseTarget { remote.setAuth(username, getGithubApiToken()); await withTempDir( - directory => + (directory) => this.pushVersionToRegistry(directory, remote, version, revision), true, - 'craft-release-registry-' + "craft-release-registry-" ); - logger.info('Release registry updated'); + logger.info("Release registry updated"); } } diff --git a/src/types/consola.d.ts b/src/types/consola.d.ts index 0d785f67..a665ad3d 100644 --- a/src/types/consola.d.ts +++ b/src/types/consola.d.ts @@ -1,4 +1,4 @@ -declare module 'consola' { +declare module "consola" { interface Consola { fatal(...message: string[]): void; error(...message: string[]): void; diff --git a/src/types/mustache.d.ts b/src/types/mustache.d.ts index b1fb5386..c7e43702 100644 --- a/src/types/mustache.d.ts +++ b/src/types/mustache.d.ts @@ -3,7 +3,7 @@ // Definitions by: Mark Ashley Bell , Manuel Thalmann , Sentry.io // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -declare module 'mustache' { +declare module "mustache" { /** * Provides the functionality to render templates with `{{mustaches}}`. */ diff --git a/src/types/nvar.ts b/src/types/nvar.ts index f969eb0f..94948582 100644 --- a/src/types/nvar.ts +++ b/src/types/nvar.ts @@ -1 +1 @@ -declare module 'nvar'; +declare module "nvar"; diff --git a/src/types/split.d.ts b/src/types/split.d.ts index 14d3e622..f0bacabc 100644 --- a/src/types/split.d.ts +++ b/src/types/split.d.ts @@ -1 +1 @@ -declare module 'split'; +declare module "split"; diff --git a/src/types/unzipper.ts b/src/types/unzipper.ts index 59348d36..cc8d630f 100644 --- a/src/types/unzipper.ts +++ b/src/types/unzipper.ts @@ -1 +1 @@ -declare module 'unzipper'; +declare module "unzipper"; diff --git a/src/utils/__fixtures__/gcsApi.ts b/src/utils/__fixtures__/gcsApi.ts index 20ed9f40..7dde0315 100644 --- a/src/utils/__fixtures__/gcsApi.ts +++ b/src/utils/__fixtures__/gcsApi.ts @@ -1,63 +1,63 @@ -import { RemoteArtifact } from '../../artifact_providers/base'; +import { RemoteArtifact } from "../../artifact_providers/base"; -export const dogsGHOrg = 'dogs-rule'; +export const dogsGHOrg = "dogs-rule"; -export const squirrelRepo = 'squirrel-operations'; +export const squirrelRepo = "squirrel-operations"; -export const squirrelBucket = 'squirrel-chasing'; +export const squirrelBucket = "squirrel-chasing"; export const squirrelSimulatorCommit = - '4d6169736579203c33203c3320436861726c6965'; + "4d6169736579203c33203c3320436861726c6965"; -export const squirrelStatsCommit = '3c3320446f67732061726520677265617421203c33'; +export const squirrelStatsCommit = "3c3320446f67732061726520677265617421203c33"; export const gcsCredsJSON = JSON.stringify({ - project_id: 'o-u-t-s-i-d-e', - private_key: 'DoGsArEgReAtSoMeSeCrEtStUfFhErE', - client_email: 'might_huntress@dogs.com', - other_stuff: 'can be anything', - tail_wagging: 'true', - barking: 'also VERY true', + project_id: "o-u-t-s-i-d-e", + private_key: "DoGsArEgReAtSoMeSeCrEtStUfFhErE", + client_email: "might_huntress@dogs.com", + other_stuff: "can be anything", + tail_wagging: "true", + barking: "also VERY true", }); export const squirrelStatsArtifact: RemoteArtifact = { - filename: 'march-2020-stats.csv', - mimeType: 'text/csv', + filename: "march-2020-stats.csv", + mimeType: "text/csv", storedFile: { - downloadFilepath: 'captured-squirrels/march-2020-stats.csv', - filename: 'march-2020-stats.csv', - lastUpdated: '2020-03-30T19:14:44.694Z', + downloadFilepath: "captured-squirrels/march-2020-stats.csv", + filename: "march-2020-stats.csv", + lastUpdated: "2020-03-30T19:14:44.694Z", size: 112112, }, }; -export const squirrelStatsLocalPath = './temp/march-2020-stats.csv'; +export const squirrelStatsLocalPath = "./temp/march-2020-stats.csv"; export const squirrelStatsBucketPath = { - path: 'stats/2020/', + path: "stats/2020/", }; export const squirrelSimulatorArtifact: RemoteArtifact = { - filename: 'bundle.js', - mimeType: 'application/json', + filename: "bundle.js", + mimeType: "application/json", storedFile: { - downloadFilepath: 'squirrel-simulator/bundle.js', - filename: 'bundle.js', - lastUpdated: '2020-03-30T19:14:44.694Z', + downloadFilepath: "squirrel-simulator/bundle.js", + filename: "bundle.js", + lastUpdated: "2020-03-30T19:14:44.694Z", size: 123112, }, }; -export const squirrelSimulatorLocalPath = './dist/bundle.js'; +export const squirrelSimulatorLocalPath = "./dist/bundle.js"; export const squirrelSimulatorBucketPath = { - path: '/simulator/v1.12.1/dist/', + path: "/simulator/v1.12.1/dist/", metadata: { cacheControl: `public, max-age=3600` }, }; export { squirrelSimulatorGCSFileObj, squirrelStatsGCSFileObj, -} from './gcsFileObj'; +} from "./gcsFileObj"; -export const tempDownloadDirectory = './temp/'; +export const tempDownloadDirectory = "./temp/"; diff --git a/src/utils/__fixtures__/gcsFileObj.ts b/src/utils/__fixtures__/gcsFileObj.ts index 32b36037..dae12262 100644 --- a/src/utils/__fixtures__/gcsFileObj.ts +++ b/src/utils/__fixtures__/gcsFileObj.ts @@ -7,12 +7,12 @@ const acl = { owners: {}, readers: {}, writers: {}, - pathPrefix: '/acl', + pathPrefix: "/acl", }; const defaultAcl = { ...acl, - pathPrefix: '/defaultObjectAcl', + pathPrefix: "/defaultObjectAcl", }; const aclWithDefault = { @@ -21,21 +21,21 @@ const aclWithDefault = { }; const aclRoles = { - OWNER_ROLE: 'OWNER', - READER_ROLE: 'READER', - WRITER_ROLE: 'WRITER', + OWNER_ROLE: "OWNER", + READER_ROLE: "READER", + WRITER_ROLE: "WRITER", }; const scopes = [ - 'https://www.googleapis.com/auth/iam', - 'https://www.googleapis.com/auth/cloud-platform', - 'https://www.googleapis.com/auth/devstorage.full_control', + "https://www.googleapis.com/auth/iam", + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/devstorage.full_control", ]; const authClient = { jsonContent: { - client_email: 'mighty_huntress@dogs.com', - private_key: 'DoGsArEgReAtSoMeSeCrEtStUfFhErE', + client_email: "mighty_huntress@dogs.com", + private_key: "DoGsArEgReAtSoMeSeCrEtStUfFhErE", }, cachedCredential: { domain: null, @@ -43,42 +43,42 @@ const authClient = { _eventsCount: 0, transporter: {}, credentials: { - access_token: 'IaMaGoOdDoGpLeAsElEtMeIn', - token_type: 'Bearer', + access_token: "IaMaGoOdDoGpLeAsElEtMeIn", + token_type: "Bearer", expiry_date: 1585600265000, - refresh_token: 'jwt-placeholder', + refresh_token: "jwt-placeholder", }, certificateExpiry: null, refreshTokenPromises: {}, eagerRefreshThresholdMillis: 300000, - email: 'mighty_huntress@dogs.com', - key: 'DoGsArEgReAtSoMeSeCrEtStUfFhErE', + email: "mighty_huntress@dogs.com", + key: "DoGsArEgReAtSoMeSeCrEtStUfFhErE", scopes, gtoken: { - token: 'IaMaGoOdDoGpLeAsElEtMeIn', + token: "IaMaGoOdDoGpLeAsElEtMeIn", expiresAt: 1585600265000, rawToken: { - access_token: 'IaMaGoOdDoGpLeAsElEtMeIn', + access_token: "IaMaGoOdDoGpLeAsElEtMeIn", expires_in: 3599, - token_type: 'Bearer', + token_type: "Bearer", }, tokenExpires: null, - key: 'DoGsArEgReAtSoMeSeCrEtStUfFhErE', - iss: 'mighty_huntress@dogs.com', + key: "DoGsArEgReAtSoMeSeCrEtStUfFhErE", + iss: "mighty_huntress@dogs.com", scope: - 'https://www.googleapis.com/auth/iam https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/devstorage.full_control', + "https://www.googleapis.com/auth/iam https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/devstorage.full_control", }, }, - _cachedProjectId: 'o-u-t-s-i-d-e', + _cachedProjectId: "o-u-t-s-i-d-e", scopes, }; const storage = { - baseUrl: 'https://www.googleapis.com/storage/v1', + baseUrl: "https://www.googleapis.com/storage/v1", globalInterceptors: [], interceptors: [], - packageJson: '', - projectId: 'o-u-t-s-i-d-e', + packageJson: "", + projectId: "o-u-t-s-i-d-e", projectIdRequired: false, authClient, acl: aclRoles, @@ -89,18 +89,18 @@ const bucket = { _events: {}, _eventsCount: 0, metadata: {}, - baseUrl: '/b', + baseUrl: "/b", parent: storage, - id: 'squirrel-chasing', + id: "squirrel-chasing", methods: { create: true, }, interceptors: [], - name: 'squirrel-chasing', + name: "squirrel-chasing", storage, acl: aclWithDefault, iam: { - resourceId_: 'buckets/[object Promise]', + resourceId_: "buckets/[object Promise]", }, }; @@ -109,34 +109,34 @@ export const squirrelStatsGCSFileObj = { _events: {}, _eventsCount: 0, metadata: { - kind: 'storage#object', - id: 'squirrel-chasing/captured-squirrels/march-2020-stats.csv/12312012', + kind: "storage#object", + id: "squirrel-chasing/captured-squirrels/march-2020-stats.csv/12312012", selfLink: - 'https://www.googleapis.com/storage/v1/b/squirrel-chasing/o/captured-squirrels%2Fmarch-2020-stats.csv', + "https://www.googleapis.com/storage/v1/b/squirrel-chasing/o/captured-squirrels%2Fmarch-2020-stats.csv", mediaLink: - 'https://www.googleapis.com/download/storage/v1/b/squirrel-chasing/o/captured-squirrels%2Fmarch-2020-stats.csv?generation=12312012&alt=media', - name: 'captured-squirrels/march-2020-stats.csv', - bucket: 'squirrel-chasing', - generation: '12312012', - metageneration: '1', - contentType: 'text/csv', - storageClass: 'STANDARD', - size: '112112', - md5Hash: 'DOX0leRinotMTM7EGGXpjQ==', - crc32c: 'fVcyCg==', - etag: 'CI/UrJz0wugCEAE=', - timeCreated: '2020-03-30T19:14:44.694Z', - updated: '2020-03-30T19:14:44.694Z', - timeStorageClassUpdated: '2020-03-30T19:14:44.694Z', + "https://www.googleapis.com/download/storage/v1/b/squirrel-chasing/o/captured-squirrels%2Fmarch-2020-stats.csv?generation=12312012&alt=media", + name: "captured-squirrels/march-2020-stats.csv", + bucket: "squirrel-chasing", + generation: "12312012", + metageneration: "1", + contentType: "text/csv", + storageClass: "STANDARD", + size: "112112", + md5Hash: "DOX0leRinotMTM7EGGXpjQ==", + crc32c: "fVcyCg==", + etag: "CI/UrJz0wugCEAE=", + timeCreated: "2020-03-30T19:14:44.694Z", + updated: "2020-03-30T19:14:44.694Z", + timeStorageClassUpdated: "2020-03-30T19:14:44.694Z", }, - baseUrl: '/o', + baseUrl: "/o", parent: bucket, - id: 'captured-squirrels%2Fmarch-2020-stats.csv', + id: "captured-squirrels%2Fmarch-2020-stats.csv", methods: {}, interceptors: [], bucket, storage, - name: 'captured-squirrels/march-2020-stats.csv', + name: "captured-squirrels/march-2020-stats.csv", acl, }; @@ -145,33 +145,33 @@ export const squirrelSimulatorGCSFileObj = { _events: {}, _eventsCount: 0, metadata: { - kind: 'storage#object', - id: 'squirrel-chasing/squirrel-simulator/bundle.js/11212012', + kind: "storage#object", + id: "squirrel-chasing/squirrel-simulator/bundle.js/11212012", selfLink: - 'https://www.googleapis.com/storage/v1/b/squirrel-chasing/o/squirrel-simulator%2Fbundle.js', + "https://www.googleapis.com/storage/v1/b/squirrel-chasing/o/squirrel-simulator%2Fbundle.js", mediaLink: - 'https://www.googleapis.com/download/storage/v1/b/squirrel-chasing/o/squirrel-simulator%2Fbundle.js?generation=11212012&alt=media', - name: 'squirrel-simulator/bundle.js', - bucket: 'squirrel-chasing', - generation: '11212012', - metageneration: '1', - contentType: 'application/javascript', - storageClass: 'STANDARD', - size: '123112', - md5Hash: 'DOX0leRinotMTM7EGGXpjQ==', - crc32c: 'fVcyCg==', - etag: 'CI/UrJz0wugCEAE=', - timeCreated: '2020-03-30T19:14:44.694Z', - updated: '2020-03-30T19:14:44.694Z', - timeStorageClassUpdated: '2020-03-30T19:14:44.694Z', + "https://www.googleapis.com/download/storage/v1/b/squirrel-chasing/o/squirrel-simulator%2Fbundle.js?generation=11212012&alt=media", + name: "squirrel-simulator/bundle.js", + bucket: "squirrel-chasing", + generation: "11212012", + metageneration: "1", + contentType: "application/javascript", + storageClass: "STANDARD", + size: "123112", + md5Hash: "DOX0leRinotMTM7EGGXpjQ==", + crc32c: "fVcyCg==", + etag: "CI/UrJz0wugCEAE=", + timeCreated: "2020-03-30T19:14:44.694Z", + updated: "2020-03-30T19:14:44.694Z", + timeStorageClassUpdated: "2020-03-30T19:14:44.694Z", }, - baseUrl: '/o', + baseUrl: "/o", parent: bucket, - id: 'squirrel-simulator%2Fbundle.js', + id: "squirrel-simulator%2Fbundle.js", methods: {}, interceptors: [], bucket, storage, - name: 'squirrel-simulator/bundle.js', + name: "squirrel-simulator/bundle.js", acl, }; diff --git a/src/utils/__tests__/async.test.ts b/src/utils/__tests__/async.test.ts index 79f96563..4f956d0e 100644 --- a/src/utils/__tests__/async.test.ts +++ b/src/utils/__tests__/async.test.ts @@ -1,27 +1,27 @@ -import { filterAsync, forEachChained, promiseProps } from '../async'; -import { logger } from '../../logger'; +import { filterAsync, forEachChained, promiseProps } from "../async"; +import { logger } from "../../logger"; -jest.mock('../../logger'); +jest.mock("../../logger"); -describe('filterAsync', () => { - test('filters with sync predicate', async () => { +describe("filterAsync", () => { + test("filters with sync predicate", async () => { expect.assertions(1); - const filtered = await filterAsync([1, 2, 3, 4], i => i > 2); + const filtered = await filterAsync([1, 2, 3, 4], (i) => i > 2); expect(filtered).toEqual([3, 4]); }); - test('filters with async predicate', async () => { + test("filters with async predicate", async () => { expect.assertions(1); const predicate = (i: number) => - new Promise(resolve => + new Promise((resolve) => setTimeout(() => resolve(i > 2), i * 100) ); const filtered = await filterAsync([1, 2, 3, 4], predicate); expect(filtered).toEqual([3, 4]); }); - test('passes filter arguments to the predicate', async () => { + test("passes filter arguments to the predicate", async () => { expect.assertions(1); const arr = [1]; @@ -31,10 +31,10 @@ describe('filterAsync', () => { expect(predicate).toHaveBeenCalledWith(1, 0, arr); }); - test('passes this to the predicate', async () => { + test("passes this to the predicate", async () => { expect.assertions(1); - const that = { key: 'value' }; + const that = { key: "value" }; await filterAsync( [1], function predicate(): any { @@ -45,52 +45,52 @@ describe('filterAsync', () => { }); }); -describe('promiseProps', () => { - test('awaits an empty object', async () => { +describe("promiseProps", () => { + test("awaits an empty object", async () => { expect.assertions(1); const result = await promiseProps({}); expect(result).toEqual({}); }); - test('awaits a plain object', async () => { + test("awaits a plain object", async () => { expect.assertions(1); - const result = await promiseProps({ foo: 'foo', bar: 42 }); - expect(result).toEqual({ foo: 'foo', bar: 42 }); + const result = await promiseProps({ foo: "foo", bar: 42 }); + expect(result).toEqual({ foo: "foo", bar: 42 }); }); - test('awaits an object with promises', async () => { + test("awaits an object with promises", async () => { expect.assertions(1); const result = await promiseProps({ bar: Promise.resolve(42), - foo: Promise.resolve('foo'), + foo: Promise.resolve("foo"), }); - expect(result).toEqual({ foo: 'foo', bar: 42 }); + expect(result).toEqual({ foo: "foo", bar: 42 }); }); }); -describe('forEachChained', () => { - test('invokes synchronous actions', async () => { +describe("forEachChained", () => { + test("invokes synchronous actions", async () => { expect.assertions(1); const fun = jest.fn(); - const arr = ['a', 'b', 'c']; + const arr = ["a", "b", "c"]; await forEachChained(arr, fun); expect(fun.mock.calls).toEqual([ - ['a', 0, arr], - ['b', 1, arr], - ['c', 2, arr], + ["a", 0, arr], + ["b", 1, arr], + ["c", 2, arr], ]); }); - test('invokes asynchronous actions sequentially', async () => { + test("invokes asynchronous actions sequentially", async () => { expect.assertions(1); const fun = jest.fn(); const arr = [500, 300, 100]; fun.mockImplementation( - timeout => new Promise(resolve => setTimeout(resolve, timeout)) + (timeout) => new Promise((resolve) => setTimeout(resolve, timeout)) ); await forEachChained(arr, fun); @@ -101,10 +101,10 @@ describe('forEachChained', () => { ]); }); - test('passes this to the action', async () => { + test("passes this to the action", async () => { expect.assertions(1); - const that = { '1': 2 }; + const that = { "1": 2 }; await forEachChained( [1], function action(): void { @@ -114,26 +114,26 @@ describe('forEachChained', () => { ); }); - describe('sync and async iteratees in regular and dry-run mode', () => { - const arr = ['first', 'second', 'third', 'fourth']; + describe("sync and async iteratees in regular and dry-run mode", () => { + const arr = ["first", "second", "third", "fourth"]; function syncIteratee(arrEntry: string): string { logger.debug(`Processing array entry \`${arrEntry}\``); - if (arrEntry === 'second' || arrEntry === 'fourth') { - throw new Error('drat'); + if (arrEntry === "second" || arrEntry === "fourth") { + throw new Error("drat"); } else { - return 'yay!'; + return "yay!"; } } function asyncIteratee(arrEntry: string): Promise { logger.debug(`Processing array entry \`${arrEntry}\``); - if (arrEntry === 'second' || arrEntry === 'fourth') { - return Promise.reject(new Error('drat')); + if (arrEntry === "second" || arrEntry === "fourth") { + return Promise.reject(new Error("drat")); } else { - return Promise.resolve('yay!'); + return Promise.resolve("yay!"); } } @@ -144,14 +144,14 @@ describe('forEachChained', () => { // check that the error does actually get thrown, the first time it hits a // problematic entry - await expect(forEachChained(arr, iteratee)).rejects.toThrowError('drat'); + await expect(forEachChained(arr, iteratee)).rejects.toThrowError("drat"); expect(logger.debug).toHaveBeenCalledWith( - 'Processing array entry `second`' + "Processing array entry `second`" ); // we didn't get this far expect(logger.debug).not.toHaveBeenCalledWith( - 'Processing array entry `third`' + "Processing array entry `third`" ); } @@ -163,12 +163,12 @@ describe('forEachChained', () => { // check that it logs the error rather than throws it await expect(forEachChained(arr, iteratee)).resolves.not.toThrowError(); expect(logger.error).toHaveBeenCalledWith( - expect.stringContaining('drat') + expect.stringContaining("drat") ); // check that it's gotten all the way through the array expect(logger.debug).toHaveBeenCalledWith( - 'Processing array entry `fourth`' + "Processing array entry `fourth`" ); } @@ -176,21 +176,21 @@ describe('forEachChained', () => { delete process.env.DRY_RUN; }); - it('blows up the first time sync iteratee errors (non-dry-run mode)', async () => { + it("blows up the first time sync iteratee errors (non-dry-run mode)", async () => { await regularModeExpectCheck(syncIteratee); }); - it('blows up the first time async iteratee errors (non-dry-run mode)', async () => { + it("blows up the first time async iteratee errors (non-dry-run mode)", async () => { await regularModeExpectCheck(asyncIteratee); }); - it('logs error but keeps going if in dry-run mode - sync iteratee', async () => { - process.env.DRY_RUN = 'true'; + it("logs error but keeps going if in dry-run mode - sync iteratee", async () => { + process.env.DRY_RUN = "true"; await dryrunModeExpectCheck(syncIteratee); }); - it('logs error but keeps going if in dry-run mode - async iteratee', async () => { - process.env.DRY_RUN = 'true'; + it("logs error but keeps going if in dry-run mode - async iteratee", async () => { + process.env.DRY_RUN = "true"; await dryrunModeExpectCheck(asyncIteratee); }); }); // end describe('sync and async iteratees in regular and dry-run mode') diff --git a/src/utils/__tests__/awsLambdaLayerManager.test.ts b/src/utils/__tests__/awsLambdaLayerManager.test.ts index 22bb6074..7235b98e 100644 --- a/src/utils/__tests__/awsLambdaLayerManager.test.ts +++ b/src/utils/__tests__/awsLambdaLayerManager.test.ts @@ -1,65 +1,65 @@ -import { DescribeRegionsCommandOutput } from '@aws-sdk/client-ec2'; -import * as awsManager from '../awsLambdaLayerManager'; +import { DescribeRegionsCommandOutput } from "@aws-sdk/client-ec2"; +import * as awsManager from "../awsLambdaLayerManager"; -const CANONICAL_SEPARATOR = ':'; +const CANONICAL_SEPARATOR = ":"; const COMPATIBLE_RUNTIME_DATA = { - name: 'test runtime', - versions: ['test version 1', 'test version 2'], + name: "test runtime", + versions: ["test version 1", "test version 2"], }; -const AWS_TEST_REGIONS = ['test aws region 1', 'test aws region 2']; +const AWS_TEST_REGIONS = ["test aws region 1", "test aws region 2"]; /** The default region used to fetch all available AWS regions. */ -const DEFAULT_REGION = 'us-east-2'; +const DEFAULT_REGION = "us-east-2"; function getTestAwsLambdaLayerManager(): awsManager.AwsLambdaLayerManager { return new awsManager.AwsLambdaLayerManager( COMPATIBLE_RUNTIME_DATA, - 'test layer name', - 'test license', + "test layer name", + "test license", Buffer.alloc(0), AWS_TEST_REGIONS ); } -describe('canonical', () => { - test('get canonical name', () => { +describe("canonical", () => { + test("get canonical name", () => { const manager = getTestAwsLambdaLayerManager(); const canonicalSuffix = manager .getCanonicalName() .split(CANONICAL_SEPARATOR)[1]; - expect(canonicalSuffix).toBe('test runtime'); + expect(canonicalSuffix).toBe("test runtime"); }); }); -describe('utils', () => { - test('account from arn', () => { - const testAccount = 'ACCOUNT_NUMBER'; +describe("utils", () => { + test("account from arn", () => { + const testAccount = "ACCOUNT_NUMBER"; const testArn = - 'arn:aws:lambda:region:' + testAccount + ':layer:layerName:version'; + "arn:aws:lambda:region:" + testAccount + ":layer:layerName:version"; expect(awsManager.getAccountFromArn(testArn)).toBe(testAccount); }); - test('get regions', async () => { + test("get regions", async () => { const regions = await awsManager.getRegionsFromAws(); expect(regions).toBe(DEFAULT_REGION); }); - test('extract region names', () => { - const testRegionName1 = 'eu-north-1'; - const testRegionName2 = 'ap-south-1'; + test("extract region names", () => { + const testRegionName1 = "eu-north-1"; + const testRegionName2 = "ap-south-1"; const regionsToExtract = { Regions: [ { - Endpoint: 'ec2.eu-north-1.amazonaws.com', + Endpoint: "ec2.eu-north-1.amazonaws.com", RegionName: testRegionName1, - OptInStatus: 'opt-in-not-required', + OptInStatus: "opt-in-not-required", }, { - Endpoint: 'ec2.ap-south-1.amazonaws.com', + Endpoint: "ec2.ap-south-1.amazonaws.com", RegionName: testRegionName2, - OptInStatus: 'opt-in-not-required', + OptInStatus: "opt-in-not-required", }, ], }; @@ -73,18 +73,18 @@ describe('utils', () => { }); }); -describe('layer publishing', () => { - test('publish to single region', async () => { - const regionTest = 'region-test'; +describe("layer publishing", () => { + test("publish to single region", async () => { + const regionTest = "region-test"; const manager = getTestAwsLambdaLayerManager(); const publishedLayer = await manager.publishLayerToRegion(regionTest); expect(publishedLayer.region).toStrictEqual(regionTest); }); - test('publish to all regions', async () => { + test("publish to all regions", async () => { const manager = getTestAwsLambdaLayerManager(); const pubishedLayers = await manager.publishToAllRegions(); - const publishedRegions = pubishedLayers.map(layer => layer.region); + const publishedRegions = pubishedLayers.map((layer) => layer.region); expect(publishedRegions).toStrictEqual(AWS_TEST_REGIONS); }); }); diff --git a/src/utils/__tests__/changes.test.ts b/src/utils/__tests__/changes.test.ts index 6714ccc7..1211cd2c 100644 --- a/src/utils/__tests__/changes.test.ts +++ b/src/utils/__tests__/changes.test.ts @@ -1,20 +1,20 @@ /* eslint-env jest */ -import { findChangeset, removeChangeset, prependChangeset } from '../changes'; +import { findChangeset, removeChangeset, prependChangeset } from "../changes"; -describe('findChangeset', () => { +describe("findChangeset", () => { const sampleChangeset = { - body: 'this is a test', - name: 'Version 1.0.0', + body: "this is a test", + name: "Version 1.0.0", }; test.each([ [ - 'regular', + "regular", `# Changelog\n## ${sampleChangeset.name}\n${sampleChangeset.body}\n`, ], [ - 'ignore date in parentheses', + "ignore date in parentheses", `# Changelog ## 1.0.1 newer @@ -27,7 +27,7 @@ describe('findChangeset', () => { `, ], [ - 'extracts a change between headings', + "extracts a change between headings", `# Changelog ## 1.0.1 newer @@ -40,11 +40,11 @@ describe('findChangeset', () => { `, ], [ - 'extracts changes from underlined headings', + "extracts changes from underlined headings", `Changelog\n====\n${sampleChangeset.name}\n----\n${sampleChangeset.body}\n`, ], [ - 'extracts changes from alternating headings', + "extracts changes from alternating headings", `# Changelog ## 1.0.1 newer @@ -57,14 +57,14 @@ describe('findChangeset', () => { older `, ], - ])('should extract %s', (_testName, markdown) => { - expect(findChangeset(markdown, 'v1.0.0')).toEqual(sampleChangeset); + ])("should extract %s", (_testName, markdown) => { + expect(findChangeset(markdown, "v1.0.0")).toEqual(sampleChangeset); }); - test('supports sub-headings', () => { + test("supports sub-headings", () => { const changeset = { - body: '### Features\nthis is a test', - name: 'Version 1.0.0', + body: "### Features\nthis is a test", + name: "Version 1.0.0", }; const markdown = `# Changelog @@ -72,13 +72,13 @@ describe('findChangeset', () => { ${changeset.body} `; - expect(findChangeset(markdown, 'v1.0.0')).toEqual(changeset); + expect(findChangeset(markdown, "v1.0.0")).toEqual(changeset); }); test.each([ - ['changeset cannot be found', 'v1.0.0'], - ['invalid version', 'not a version'], - ])('should return null on %s', (_testName, version) => { + ["changeset cannot be found", "v1.0.0"], + ["invalid version", "not a version"], + ])("should return null on %s", (_testName, version) => { const markdown = `# Changelog ## 1.0.1 newer @@ -92,8 +92,8 @@ describe('findChangeset', () => { test.each([ [ - 'remove from the top', - '1.0.1', + "remove from the top", + "1.0.1", `# Changelog 1.0.0 ------- @@ -107,8 +107,8 @@ test.each([ `, ], [ - 'remove from the middle', - '0.9.1', + "remove from the middle", + "0.9.1", `# Changelog ## 1.0.1 newer @@ -122,8 +122,8 @@ test.each([ `, ], [ - 'remove from underlined', - '1.0.0', + "remove from underlined", + "1.0.0", `# Changelog ## 1.0.1 newer @@ -136,8 +136,8 @@ test.each([ `, ], [ - 'remove from the bottom', - '0.9.0', + "remove from the bottom", + "0.9.0", `# Changelog ## 1.0.1 newer @@ -152,8 +152,8 @@ test.each([ `, ], [ - 'not remove missing', - 'non-existent version', + "not remove missing", + "non-existent version", `# Changelog ## 1.0.1 newer @@ -170,8 +170,8 @@ test.each([ `, ], [ - 'not remove empty', - '', + "not remove empty", + "", `# Changelog ## 1.0.1 newer @@ -187,7 +187,7 @@ test.each([ older `, ], -])('remove changeset should %s', (_testName, header, expected) => { +])("remove changeset should %s", (_testName, header, expected) => { const markdown = `# Changelog ## 1.0.1 newer @@ -208,45 +208,45 @@ test.each([ test.each([ [ - 'prepend to empty text', - '', - '## 2.0.0\n\nrewrote everything from scratch\n\n', + "prepend to empty text", + "", + "## 2.0.0\n\nrewrote everything from scratch\n\n", ], [ - 'prepend without top-level header', - '## 1.0.0\n\nthis is a test\n', - '## 2.0.0\n\nrewrote everything from scratch\n\n## 1.0.0\n\nthis is a test\n', + "prepend without top-level header", + "## 1.0.0\n\nthis is a test\n", + "## 2.0.0\n\nrewrote everything from scratch\n\n## 1.0.0\n\nthis is a test\n", ], [ - 'prepend after top-level header (empty body)', - '# Changelog\n', - '# Changelog\n## 2.0.0\n\nrewrote everything from scratch\n\n', + "prepend after top-level header (empty body)", + "# Changelog\n", + "# Changelog\n## 2.0.0\n\nrewrote everything from scratch\n\n", ], [ - 'prepend after top-level header', - '# Changelog\n\n## 1.0.0\n\nthis is a test\n', - '# Changelog\n\n## 2.0.0\n\nrewrote everything from scratch\n\n## 1.0.0\n\nthis is a test\n', + "prepend after top-level header", + "# Changelog\n\n## 1.0.0\n\nthis is a test\n", + "# Changelog\n\n## 2.0.0\n\nrewrote everything from scratch\n\n## 1.0.0\n\nthis is a test\n", ], [ - 'prepend with underlined when detected', - '# Changelog\n\n1.0.0\n-----\n\nthis is a test\n', - '# Changelog\n\n2.0.0\n-----\n\nrewrote everything from scratch\n\n1.0.0\n-----\n\nthis is a test\n', + "prepend with underlined when detected", + "# Changelog\n\n1.0.0\n-----\n\nthis is a test\n", + "# Changelog\n\n2.0.0\n-----\n\nrewrote everything from scratch\n\n1.0.0\n-----\n\nthis is a test\n", ], [ - 'prepend with consistent padding with the rest', - '# Changelog\n\n ## 1.0.0\n\n this is a test\n', - '# Changelog\n\n ## 2.0.0\n\n rewrote everything from scratch\n\n ## 1.0.0\n\n this is a test\n', + "prepend with consistent padding with the rest", + "# Changelog\n\n ## 1.0.0\n\n this is a test\n", + "# Changelog\n\n ## 2.0.0\n\n rewrote everything from scratch\n\n ## 1.0.0\n\n this is a test\n", ], [ - 'prepend with consistent padding with the rest (underlined)', - '# Changelog\n\n 1.0.0\n-----\n\n this is a test\n', - '# Changelog\n\n 2.0.0\n-----\n\n rewrote everything from scratch\n\n 1.0.0\n-----\n\n this is a test\n', + "prepend with consistent padding with the rest (underlined)", + "# Changelog\n\n 1.0.0\n-----\n\n this is a test\n", + "# Changelog\n\n 2.0.0\n-----\n\n rewrote everything from scratch\n\n 1.0.0\n-----\n\n this is a test\n", ], -])('prependChangeset should %s', (_testName, markdown, expected) => { +])("prependChangeset should %s", (_testName, markdown, expected) => { expect( prependChangeset(markdown, { - body: 'rewrote everything from scratch', - name: '2.0.0', + body: "rewrote everything from scratch", + name: "2.0.0", }) ).toEqual(expected); }); diff --git a/src/utils/__tests__/env.test.ts b/src/utils/__tests__/env.test.ts index 9b404801..fbc69a63 100644 --- a/src/utils/__tests__/env.test.ts +++ b/src/utils/__tests__/env.test.ts @@ -1,22 +1,22 @@ -import { writeFileSync } from 'fs'; -import { join } from 'path'; -const os = require('os'); +import { writeFileSync } from "fs"; +import { join } from "path"; +const os = require("os"); -import * as config from '../../config'; +import * as config from "../../config"; import { checkEnvForPrerequisite, readEnvironmentConfig, ENV_FILE_NAME, -} from '../env'; -import { ConfigurationError } from '../errors'; -import { logger } from '../../logger'; -import { withTempDir } from '../files'; +} from "../env"; +import { ConfigurationError } from "../errors"; +import { logger } from "../../logger"; +import { withTempDir } from "../files"; -jest.mock('../../logger'); -const homedirMock = jest.spyOn(os, 'homedir'); -const getConfigFileDirMock = jest.spyOn(config, 'getConfigFileDir'); +jest.mock("../../logger"); +const homedirMock = jest.spyOn(os, "homedir"); +const getConfigFileDirMock = jest.spyOn(config, "getConfigFileDir"); -describe('env utils functions', () => { +describe("env utils functions", () => { const cleanEnv = { ...process.env }; beforeEach(() => { @@ -24,141 +24,141 @@ describe('env utils functions', () => { jest.resetAllMocks(); }); - describe('checkEnvForPrerequisite', () => { - it('runs', () => { - process.env.DOGS = 'RULE'; // just to prevent the function erroring - checkEnvForPrerequisite({ name: 'DOGS' }); + describe("checkEnvForPrerequisite", () => { + it("runs", () => { + process.env.DOGS = "RULE"; // just to prevent the function erroring + checkEnvForPrerequisite({ name: "DOGS" }); expect(logger.debug).toHaveBeenCalledWith( - expect.stringContaining('Checking for environment variable DOGS') + expect.stringContaining("Checking for environment variable DOGS") ); }); - describe('no legacy name', () => { - it('finds correctly set var', () => { - process.env.DOGS = 'RULE'; - checkEnvForPrerequisite({ name: 'DOGS' }); + describe("no legacy name", () => { + it("finds correctly set var", () => { + process.env.DOGS = "RULE"; + checkEnvForPrerequisite({ name: "DOGS" }); expect(logger.debug).toHaveBeenCalledWith(`Found DOGS`); }); - it('errors if var not set', () => { - expect(() => checkEnvForPrerequisite({ name: 'DOGS' })).toThrowError( + it("errors if var not set", () => { + expect(() => checkEnvForPrerequisite({ name: "DOGS" })).toThrowError( ConfigurationError ); }); }); // end describe('no legacy name') - describe('with legacy name', () => { - it('handles both new and legacy variable being set', () => { - process.env.DOGS = 'RULE'; - process.env.CATS = 'DROOL'; - checkEnvForPrerequisite({ name: 'DOGS', legacyName: 'CATS' }); + describe("with legacy name", () => { + it("handles both new and legacy variable being set", () => { + process.env.DOGS = "RULE"; + process.env.CATS = "DROOL"; + checkEnvForPrerequisite({ name: "DOGS", legacyName: "CATS" }); expect(logger.warn).toHaveBeenCalledWith( `When searching configuration files and your environment, found DOGS ` + `but also found legacy CATS. Do you mean to be using both?` ); }); - it('handles only new variable being set', () => { - process.env.DOGS = 'RULE'; - checkEnvForPrerequisite({ name: 'DOGS', legacyName: 'CATS' }); - expect(logger.debug).toHaveBeenCalledWith('Found DOGS'); + it("handles only new variable being set", () => { + process.env.DOGS = "RULE"; + checkEnvForPrerequisite({ name: "DOGS", legacyName: "CATS" }); + expect(logger.debug).toHaveBeenCalledWith("Found DOGS"); }); - it('handles only legacy variable being set, and copies value to new variable', () => { - process.env.CATS = 'DROOL'; - checkEnvForPrerequisite({ name: 'DOGS', legacyName: 'CATS' }); + it("handles only legacy variable being set, and copies value to new variable", () => { + process.env.CATS = "DROOL"; + checkEnvForPrerequisite({ name: "DOGS", legacyName: "CATS" }); expect(logger.warn).toHaveBeenCalledWith( `Usage of CATS is deprecated, and will be removed in later versions. ` + `Please use DOGS instead.` ); - expect(process.env.DOGS).toEqual('DROOL'); + expect(process.env.DOGS).toEqual("DROOL"); }); - it('errors if neither is set', () => { + it("errors if neither is set", () => { expect(() => - checkEnvForPrerequisite({ name: 'DOGS', legacyName: 'CATS' }) + checkEnvForPrerequisite({ name: "DOGS", legacyName: "CATS" }) ).toThrowError(ConfigurationError); }); }); // end describe('with legacy name') - describe('multiple options', () => { - it('checks for multiple variables', () => { + describe("multiple options", () => { + it("checks for multiple variables", () => { // don't set either variable to force it to look for both (but that makes // it error, so `expect` the error to catch it so it doesn't break the // test) expect(() => - checkEnvForPrerequisite({ name: 'MAISEY' }, { name: 'CHARLIE' }) + checkEnvForPrerequisite({ name: "MAISEY" }, { name: "CHARLIE" }) ).toThrowError(ConfigurationError); expect(logger.debug).toHaveBeenCalledWith( `Checking for environment variable(s) MAISEY or CHARLIE` ); expect(logger.debug).toHaveBeenCalledWith( - expect.stringContaining('Checking for environment variable MAISEY') + expect.stringContaining("Checking for environment variable MAISEY") ); expect(logger.debug).toHaveBeenCalledWith( - expect.stringContaining('Checking for environment variable CHARLIE') + expect.stringContaining("Checking for environment variable CHARLIE") ); }); - it('is happy if either option is defined', () => { - process.env.MAISEY = 'GOOD DOG'; + it("is happy if either option is defined", () => { + process.env.MAISEY = "GOOD DOG"; expect(() => - checkEnvForPrerequisite({ name: 'MAISEY' }, { name: 'CHARLIE' }) + checkEnvForPrerequisite({ name: "MAISEY" }, { name: "CHARLIE" }) ).not.toThrowError(ConfigurationError); - expect(logger.debug).toHaveBeenCalledWith('Found MAISEY'); + expect(logger.debug).toHaveBeenCalledWith("Found MAISEY"); delete process.env.MAISEY; - process.env.CHARLIE = 'ALSO GOOD DOG'; + process.env.CHARLIE = "ALSO GOOD DOG"; expect(() => - checkEnvForPrerequisite({ name: 'MAISEY' }, { name: 'CHARLIE' }) + checkEnvForPrerequisite({ name: "MAISEY" }, { name: "CHARLIE" }) ).not.toThrowError(ConfigurationError); - expect(logger.debug).toHaveBeenCalledWith('Found CHARLIE'); + expect(logger.debug).toHaveBeenCalledWith("Found CHARLIE"); }); - it('throws if neither one is defined', () => { + it("throws if neither one is defined", () => { // skip defining vars here expect(() => - checkEnvForPrerequisite({ name: 'MAISEY' }, { name: 'CHARLIE' }) + checkEnvForPrerequisite({ name: "MAISEY" }, { name: "CHARLIE" }) ).toThrowError(ConfigurationError); }); - it('handles a mix of variables with and without legacy names', () => { - process.env.MAISEY = 'GOOD DOG'; + it("handles a mix of variables with and without legacy names", () => { + process.env.MAISEY = "GOOD DOG"; expect(() => checkEnvForPrerequisite( - { name: 'MAISEY' }, - { name: 'CHARLIE', legacyName: 'OPAL' } + { name: "MAISEY" }, + { name: "CHARLIE", legacyName: "OPAL" } ) ).not.toThrowError(ConfigurationError); - expect(logger.debug).toHaveBeenCalledWith('Found MAISEY'); + expect(logger.debug).toHaveBeenCalledWith("Found MAISEY"); delete process.env.MAISEY; - process.env.OPAL = 'GOOD PUPPY'; + process.env.OPAL = "GOOD PUPPY"; expect(() => checkEnvForPrerequisite( - { name: 'MAISEY' }, - { name: 'CHARLIE', legacyName: 'OPAL' } + { name: "MAISEY" }, + { name: "CHARLIE", legacyName: "OPAL" } ) ).not.toThrowError(ConfigurationError); expect(logger.warn).toHaveBeenCalledWith( `Usage of OPAL is deprecated, and will be removed in later versions. ` + `Please use CHARLIE instead.` ); - expect(process.env.CHARLIE).toEqual('GOOD PUPPY'); + expect(process.env.CHARLIE).toEqual("GOOD PUPPY"); }); }); // end describe('multiple variables') }); // end describe('checkEnvForPrerequisites') - describe('readEnvironmentConfig', () => { - const invalidDir = '/invalid/invalid'; + describe("readEnvironmentConfig", () => { + const invalidDir = "/invalid/invalid"; function writeConfigFileSync(directory: string): void { const outConfigFile = join(directory, config.CONFIG_FILE_NAME); - writeFileSync(outConfigFile, ''); + writeFileSync(outConfigFile, ""); } - test('calls homedir/findConfigFile', () => { - process.env.TEST_BLA = '123'; + test("calls homedir/findConfigFile", () => { + process.env.TEST_BLA = "123"; homedirMock.mockReturnValue(invalidDir); getConfigFileDirMock.mockReturnValue(invalidDir); @@ -167,92 +167,92 @@ describe('env utils functions', () => { expect(getConfigFileDirMock).toHaveBeenCalledTimes(1); expect(homedirMock).toHaveBeenCalledTimes(1); - expect(process.env.TEST_BLA).toBe('123'); + expect(process.env.TEST_BLA).toBe("123"); expect(ENV_FILE_NAME.length).toBeGreaterThanOrEqual(1); }); - test('checks the config directory', async () => { + test("checks the config directory", async () => { homedirMock.mockReturnValue(invalidDir); - await withTempDir(directory => { + await withTempDir((directory) => { getConfigFileDirMock.mockReturnValue(directory); writeConfigFileSync(directory); const outFile = join(directory, ENV_FILE_NAME); - writeFileSync(outFile, 'export TEST_BLA=234\nexport TEST_ANOTHER=345'); + writeFileSync(outFile, "export TEST_BLA=234\nexport TEST_ANOTHER=345"); readEnvironmentConfig(); - expect(process.env.TEST_BLA).toBe('234'); + expect(process.env.TEST_BLA).toBe("234"); }); }); - test('checks home directory', async () => { + test("checks home directory", async () => { getConfigFileDirMock.mockReturnValue(invalidDir); - await withTempDir(directory => { + await withTempDir((directory) => { homedirMock.mockReturnValue(directory); const outFile = join(directory, ENV_FILE_NAME); - writeFileSync(outFile, 'export TEST_BLA=234\n'); + writeFileSync(outFile, "export TEST_BLA=234\n"); readEnvironmentConfig(); - expect(process.env.TEST_BLA).toBe('234'); + expect(process.env.TEST_BLA).toBe("234"); }); }); - test('checks home directory first, and then the config directory', async () => { - await withTempDir(async dir1 => { - await withTempDir(dir2 => { + test("checks home directory first, and then the config directory", async () => { + await withTempDir(async (dir1) => { + await withTempDir((dir2) => { homedirMock.mockReturnValue(dir1); const outHome = join(dir1, ENV_FILE_NAME); - writeFileSync(outHome, 'export TEST_BLA=from_home'); + writeFileSync(outHome, "export TEST_BLA=from_home"); getConfigFileDirMock.mockReturnValue(dir2); writeConfigFileSync(dir2); const configDirFile = join(dir2, ENV_FILE_NAME); - writeFileSync(configDirFile, 'export TEST_BLA=from_config_dir'); + writeFileSync(configDirFile, "export TEST_BLA=from_config_dir"); readEnvironmentConfig(); - expect(process.env.TEST_BLA).toBe('from_config_dir'); + expect(process.env.TEST_BLA).toBe("from_config_dir"); }); }); }); - test('does not overwrite existing variables by default', async () => { + test("does not overwrite existing variables by default", async () => { homedirMock.mockReturnValue(invalidDir); - process.env.TEST_BLA = 'existing'; + process.env.TEST_BLA = "existing"; - await withTempDir(directory => { + await withTempDir((directory) => { getConfigFileDirMock.mockReturnValue(directory); const outFile = join(directory, ENV_FILE_NAME); - writeFileSync(outFile, 'export TEST_BLA=new_value'); + writeFileSync(outFile, "export TEST_BLA=new_value"); readEnvironmentConfig(); - expect(process.env.TEST_BLA).toBe('existing'); + expect(process.env.TEST_BLA).toBe("existing"); }); }); - test('overwrites existing variables if explicitly stated', async () => { + test("overwrites existing variables if explicitly stated", async () => { homedirMock.mockReturnValue(invalidDir); - process.env.TEST_BLA = 'existing'; + process.env.TEST_BLA = "existing"; - await withTempDir(directory => { + await withTempDir((directory) => { getConfigFileDirMock.mockReturnValue(directory); writeConfigFileSync(directory); const outFile = join(directory, ENV_FILE_NAME); - writeFileSync(outFile, 'export TEST_BLA=new_value'); + writeFileSync(outFile, "export TEST_BLA=new_value"); readEnvironmentConfig(true); - expect(process.env.TEST_BLA).toBe('new_value'); + expect(process.env.TEST_BLA).toBe("new_value"); }); }); }); // end describe('readEnvironmentConfig') diff --git a/src/utils/__tests__/errors.test.ts b/src/utils/__tests__/errors.test.ts index e4096229..ec73d26d 100644 --- a/src/utils/__tests__/errors.test.ts +++ b/src/utils/__tests__/errors.test.ts @@ -1,20 +1,20 @@ -import { coerceType } from '../errors'; +import { coerceType } from "../errors"; -describe('coerceType', () => { - test('asserts a string correctly', async () => { - expect(coerceType('test', 'string')).toBe('test'); +describe("coerceType", () => { + test("asserts a string correctly", async () => { + expect(coerceType("test", "string")).toBe("test"); }); - test('asserts a number correctly', async () => { - expect(coerceType(123, 'number')).toBe(123); + test("asserts a number correctly", async () => { + expect(coerceType(123, "number")).toBe(123); }); - test('throws an error if the type is incorrect', async () => { - expect(() => coerceType(123, 'function')).toThrowError(TypeError); + test("throws an error if the type is incorrect", async () => { + expect(() => coerceType(123, "function")).toThrowError(TypeError); }); - test('throws an error with a custom message', async () => { - const customMsg = 'custom message'; - expect(() => coerceType({}, 'number', customMsg)).toThrowError(customMsg); + test("throws an error with a custom message", async () => { + const customMsg = "custom message"; + expect(() => coerceType({}, "number", customMsg)).toThrowError(customMsg); }); }); diff --git a/src/utils/__tests__/files.test.ts b/src/utils/__tests__/files.test.ts index c5763521..bf966ce9 100644 --- a/src/utils/__tests__/files.test.ts +++ b/src/utils/__tests__/files.test.ts @@ -1,27 +1,27 @@ -import { existsSync, rmdirSync } from 'fs'; -import { join, resolve } from 'path'; +import { existsSync, rmdirSync } from "fs"; +import { join, resolve } from "path"; -import { listFiles, withTempDir } from '../files'; +import { listFiles, withTempDir } from "../files"; -describe('listFiles', () => { - const testDir = resolve(__dirname, '../__fixtures__/listFiles'); - const testFiles = ['a', 'b'].map(f => join(testDir, f)); +describe("listFiles", () => { + const testDir = resolve(__dirname, "../__fixtures__/listFiles"); + const testFiles = ["a", "b"].map((f) => join(testDir, f)); - test('returns only files', async () => { + test("returns only files", async () => { expect.assertions(1); const files = await listFiles(testDir); expect(files).toEqual(testFiles); }); }); -describe('withTempDir', () => { +describe("withTempDir", () => { async function testDirectories( callback: (arg: any) => any, cleanupEnabled = true ): Promise { - let directory = ''; + let directory = ""; try { - await withTempDir(dir => { + await withTempDir((dir) => { directory = dir; expect(existsSync(directory)).toBeTruthy(); return callback(directory); @@ -30,7 +30,7 @@ describe('withTempDir', () => { if (cleanupEnabled) { // We intentionally do not block on the clean up operation // so wait ~100ms before checking - await new Promise(resolve => setTimeout(resolve, 100)); + await new Promise((resolve) => setTimeout(resolve, 100)); expect(existsSync(directory)).toBeFalsy(); } else { expect(existsSync(directory)).toBeTruthy(); @@ -38,55 +38,55 @@ describe('withTempDir', () => { } } - test('creates and removes synchronously', async () => { + test("creates and removes synchronously", async () => { expect.assertions(2); await testDirectories(() => true); }); - test('creates and removes on error', async () => { + test("creates and removes on error", async () => { try { expect.assertions(3); await testDirectories(() => { - throw new Error('fail'); + throw new Error("fail"); }); } catch (e) { - expect(e.message).toBe('fail'); + expect(e.message).toBe("fail"); } }); - test('creates and does not remove if cleanup flag is specified', async () => { + test("creates and does not remove if cleanup flag is specified", async () => { expect.assertions(2); - let tempDir = ''; - await testDirectories(arg => { + let tempDir = ""; + await testDirectories((arg) => { tempDir = arg; }, false); // Cleanup rmdirSync(tempDir); }); - test('creates and removes on Promise resolution', async () => { + test("creates and removes on Promise resolution", async () => { expect.assertions(2); - await testDirectories(() => Promise.resolve('success')); + await testDirectories(() => Promise.resolve("success")); }); - test('creates and removes on Promise rejection', async () => { + test("creates and removes on Promise rejection", async () => { try { expect.assertions(3); - await testDirectories(() => Promise.reject(new Error('fail'))); + await testDirectories(() => Promise.reject(new Error("fail"))); } catch (e) { - expect(e.message).toBe('fail'); + expect(e.message).toBe("fail"); } }); - test('returns the callback return value synchronously', async () => { + test("returns the callback return value synchronously", async () => { expect.assertions(1); - const result = await withTempDir(() => 'result'); - expect(result).toBe('result'); + const result = await withTempDir(() => "result"); + expect(result).toBe("result"); }); - test('returns the callback return value asynchronously', async () => { + test("returns the callback return value asynchronously", async () => { expect.assertions(1); - const result = await withTempDir(() => Promise.resolve('result')); - expect(result).toBe('result'); + const result = await withTempDir(() => Promise.resolve("result")); + expect(result).toBe("result"); }); }); diff --git a/src/utils/__tests__/filters.test.ts b/src/utils/__tests__/filters.test.ts index 58bf55fe..3ee38631 100644 --- a/src/utils/__tests__/filters.test.ts +++ b/src/utils/__tests__/filters.test.ts @@ -1,30 +1,30 @@ -import { stringToRegexp } from '../filters'; +import { stringToRegexp } from "../filters"; -describe('stringToRegexp', () => { - test('converts string without special characters', () => { - expect(stringToRegexp('/simple/')).toEqual(/simple/); +describe("stringToRegexp", () => { + test("converts string without special characters", () => { + expect(stringToRegexp("/simple/")).toEqual(/simple/); }); - test('converts string with special characters', () => { - expect(stringToRegexp('/sim.le\\d+/')).toEqual(/sim.le\d+/); + test("converts string with special characters", () => { + expect(stringToRegexp("/sim.le\\d+/")).toEqual(/sim.le\d+/); }); - test('uses regexp modifiers', () => { - expect(stringToRegexp('/[!?]{2}\\w+/gi')).toEqual(/[!?]{2}\w+/gi); + test("uses regexp modifiers", () => { + expect(stringToRegexp("/[!?]{2}\\w+/gi")).toEqual(/[!?]{2}\w+/gi); }); - test('is not confused by multiple slashes', () => { - expect(stringToRegexp('/file1/file2/i')).toEqual(/file1\/file2/i); + test("is not confused by multiple slashes", () => { + expect(stringToRegexp("/file1/file2/i")).toEqual(/file1\/file2/i); }); - test('is source of regex what we think', () => { - expect(stringToRegexp('/none/').source).toEqual('none'); + test("is source of regex what we think", () => { + expect(stringToRegexp("/none/").source).toEqual("none"); }); - test('raises an error if the value is not surrounded by slashes', () => { + test("raises an error if the value is not surrounded by slashes", () => { expect.assertions(1); try { - stringToRegexp('no-slashes'); + stringToRegexp("no-slashes"); } catch (e) { expect(e.message).toMatch(/invalid regexp/i); } diff --git a/src/utils/__tests__/gcsAPI.test.ts b/src/utils/__tests__/gcsAPI.test.ts index a6799635..ac8ccaab 100644 --- a/src/utils/__tests__/gcsAPI.test.ts +++ b/src/utils/__tests__/gcsAPI.test.ts @@ -1,12 +1,12 @@ -import * as fs from 'fs'; -import * as path from 'path'; +import * as fs from "fs"; +import * as path from "path"; import { getGCSCredsFromEnv, CraftGCSClient, DEFAULT_UPLOAD_METADATA, -} from '../gcsApi'; -import { withTempFile, withTempDir } from '../files'; +} from "../gcsApi"; +import { withTempFile, withTempDir } from "../files"; import { dogsGHOrg, @@ -23,16 +23,16 @@ import { squirrelStatsGCSFileObj, squirrelStatsCommit, squirrelSimulatorGCSFileObj, -} from '../__fixtures__/gcsApi'; +} from "../__fixtures__/gcsApi"; /*************** mocks and other setup ***************/ -jest.mock('../../logger'); +jest.mock("../../logger"); const mockGCSUpload = jest.fn(); const mockGCSDownload = jest.fn(); const mockGCSGetFiles = jest.fn(); -jest.mock('@google-cloud/storage', () => ({ +jest.mock("@google-cloud/storage", () => ({ Bucket: jest.fn(() => ({ file: jest.fn(() => ({ download: mockGCSDownload })), getFiles: mockGCSGetFiles, @@ -41,22 +41,22 @@ jest.mock('@google-cloud/storage', () => ({ Storage: jest.fn(() => ({})), })); -const syncExistsSpy = jest.spyOn(fs, 'existsSync'); +const syncExistsSpy = jest.spyOn(fs, "existsSync"); const cleanEnv = { ...process.env }; const client = new CraftGCSClient({ bucketName: squirrelBucket, credentials: { - client_email: 'mighty_huntress@dogs.com', - private_key: 'DoGsArEgReAtSoMeSeCrEtStUfFhErE', + client_email: "mighty_huntress@dogs.com", + private_key: "DoGsArEgReAtSoMeSeCrEtStUfFhErE", }, - projectId: 'o-u-t-s-i-d-e', + projectId: "o-u-t-s-i-d-e", }); /*************** the actual tests ***************/ -describe('gcsApi module', () => { +describe("gcsApi module", () => { afterEach(() => { // in case we've modified the env in any way, reset it process.env = { ...cleanEnv }; @@ -66,77 +66,77 @@ describe('gcsApi module', () => { jest.clearAllMocks(); }); - describe('getGCSCredsFromEnv', () => { - it('pulls JSON creds from env', () => { + describe("getGCSCredsFromEnv", () => { + it("pulls JSON creds from env", () => { process.env.DOG_CREDS_JSON = gcsCredsJSON; const { project_id, client_email, private_key } = getGCSCredsFromEnv( - { name: 'DOG_CREDS_JSON' }, - { name: 'DOG_CREDS_PATH' } + { name: "DOG_CREDS_JSON" }, + { name: "DOG_CREDS_PATH" } ); - expect(project_id).toEqual('o-u-t-s-i-d-e'); - expect(client_email).toEqual('might_huntress@dogs.com'); - expect(private_key).toEqual('DoGsArEgReAtSoMeSeCrEtStUfFhErE'); + expect(project_id).toEqual("o-u-t-s-i-d-e"); + expect(client_email).toEqual("might_huntress@dogs.com"); + expect(private_key).toEqual("DoGsArEgReAtSoMeSeCrEtStUfFhErE"); }); - it('pulls filepath creds from env', async () => { + it("pulls filepath creds from env", async () => { // ensure that the assertions below actually happen, since they in an async // function expect.assertions(3); - await withTempFile(tempFilepath => { + await withTempFile((tempFilepath) => { fs.writeFileSync(tempFilepath, gcsCredsJSON); process.env.DOG_CREDS_PATH = tempFilepath; const { project_id, client_email, private_key } = getGCSCredsFromEnv( - { name: 'DOG_CREDS_JSON' }, - { name: 'DOG_CREDS_PATH' } + { name: "DOG_CREDS_JSON" }, + { name: "DOG_CREDS_PATH" } ); - expect(project_id).toEqual('o-u-t-s-i-d-e'); - expect(client_email).toEqual('might_huntress@dogs.com'); - expect(private_key).toEqual('DoGsArEgReAtSoMeSeCrEtStUfFhErE'); + expect(project_id).toEqual("o-u-t-s-i-d-e"); + expect(client_email).toEqual("might_huntress@dogs.com"); + expect(private_key).toEqual("DoGsArEgReAtSoMeSeCrEtStUfFhErE"); }); }); - it('errors if neither JSON creds nor creds filepath provided', () => { + it("errors if neither JSON creds nor creds filepath provided", () => { // skip defining variables expect(() => { getGCSCredsFromEnv( - { name: 'DOG_CREDS_JSON' }, - { name: 'DOG_CREDS_PATH' } + { name: "DOG_CREDS_JSON" }, + { name: "DOG_CREDS_PATH" } ); - }).toThrowError('GCS credentials not found!'); + }).toThrowError("GCS credentials not found!"); }); - it('errors if given bogus JSON', () => { + it("errors if given bogus JSON", () => { process.env.DOG_CREDS_JSON = `Dogs!`; expect(() => { getGCSCredsFromEnv( - { name: 'DOG_CREDS_JSON' }, - { name: 'DOG_CREDS_PATH' } + { name: "DOG_CREDS_JSON" }, + { name: "DOG_CREDS_PATH" } ); - }).toThrowError('Error parsing JSON credentials'); + }).toThrowError("Error parsing JSON credentials"); }); - it('errors if creds file missing from given path', () => { - process.env.DOG_CREDS_PATH = './iDontExist.json'; + it("errors if creds file missing from given path", () => { + process.env.DOG_CREDS_PATH = "./iDontExist.json"; // make sure it won't find the file syncExistsSpy.mockReturnValueOnce(false); expect(() => { getGCSCredsFromEnv( - { name: 'DOG_CREDS_JSON' }, - { name: 'DOG_CREDS_PATH' } + { name: "DOG_CREDS_JSON" }, + { name: "DOG_CREDS_PATH" } ); - }).toThrowError('File does not exist: `./iDontExist.json`!'); + }).toThrowError("File does not exist: `./iDontExist.json`!"); }); - it('errors if necessary field missing', () => { + it("errors if necessary field missing", () => { process.env.DOG_CREDS_JSON = `{ "project_id": "o-u-t-s-i-d-e", "private_key": "DoGsArEgReAtSoMeSeCrEtStUfFhErE" @@ -144,16 +144,16 @@ describe('gcsApi module', () => { expect(() => { getGCSCredsFromEnv( - { name: 'DOG_CREDS_JSON' }, - { name: 'DOG_CREDS_PATH' } + { name: "DOG_CREDS_JSON" }, + { name: "DOG_CREDS_PATH" } ); - }).toThrowError('GCS credentials missing `client_email`!'); + }).toThrowError("GCS credentials missing `client_email`!"); }); }); // end describe('getGCSCredsFromEnv') - describe('CraftGCSClient class', () => { - describe('upload', () => { - it('calls the GCS library upload method with the right parameters', async () => { + describe("CraftGCSClient class", () => { + describe("upload", () => { + it("calls the GCS library upload method with the right parameters", async () => { expect.assertions(1); await client.uploadArtifact( @@ -174,11 +174,11 @@ describe('gcsApi module', () => { }); }); - it('removes leading slashes in upload destinations', async () => { + it("removes leading slashes in upload destinations", async () => { expect.assertions(1); await client.uploadArtifact(squirrelStatsLocalPath, { - path: '/' + squirrelStatsBucketPath.path, + path: "/" + squirrelStatsBucketPath.path, }); const { filename } = squirrelStatsArtifact; @@ -194,7 +194,7 @@ describe('gcsApi module', () => { }); }); - it('detects content type correctly for JS and map files', async () => { + it("detects content type correctly for JS and map files", async () => { expect.assertions(1); await client.uploadArtifact( @@ -206,13 +206,13 @@ describe('gcsApi module', () => { squirrelSimulatorLocalPath, expect.objectContaining({ metadata: expect.objectContaining({ - contentType: 'application/javascript; charset=utf-8', + contentType: "application/javascript; charset=utf-8", }), }) ); }); - it('allows overriding of default metadata', async () => { + it("allows overriding of default metadata", async () => { expect.assertions(1); await client.uploadArtifact( @@ -230,11 +230,11 @@ describe('gcsApi module', () => { ); }); - it('errors if GCS upload goes sideways', async () => { + it("errors if GCS upload goes sideways", async () => { expect.assertions(1); mockGCSUpload.mockImplementation(() => { - throw new Error('The squirrel got away!'); + throw new Error("The squirrel got away!"); }); const { filename } = squirrelSimulatorArtifact; @@ -252,7 +252,7 @@ describe('gcsApi module', () => { it("doesn't upload anything in dry run mode", async () => { expect.assertions(1); - process.env.DRY_RUN = 'true'; + process.env.DRY_RUN = "true"; await client.uploadArtifact( squirrelStatsLocalPath, @@ -263,11 +263,11 @@ describe('gcsApi module', () => { }); }); // end describe('upload') - describe('download', () => { - it('calls the GCS library download method with the right parameters', async () => { + describe("download", () => { + it("calls the GCS library download method with the right parameters", async () => { expect.assertions(1); - await withTempDir(async tempDownloadDirectory => { + await withTempDir(async (tempDownloadDirectory) => { await client.downloadArtifact( squirrelStatsArtifact.storedFile.downloadFilepath, tempDownloadDirectory @@ -290,17 +290,17 @@ describe('gcsApi module', () => { await expect( client.downloadArtifact( squirrelSimulatorArtifact.storedFile.downloadFilepath, - './iDontExist/' + "./iDontExist/" ) ).rejects.toThrowError(`directory does not exist!`); }); - it('errors if GCS download goes sideways', async () => { + it("errors if GCS download goes sideways", async () => { expect.assertions(1); - await withTempDir(async tempDownloadDirectory => { + await withTempDir(async (tempDownloadDirectory) => { mockGCSDownload.mockImplementation(() => { - throw new Error('The squirrel got away!'); + throw new Error("The squirrel got away!"); }); const { filename } = squirrelSimulatorArtifact; @@ -317,10 +317,10 @@ describe('gcsApi module', () => { }); it("doesn't upload anything in dry run mode", async () => { - await withTempDir(async tempDownloadDirectory => { + await withTempDir(async (tempDownloadDirectory) => { expect.assertions(1); - process.env.DRY_RUN = 'true'; + process.env.DRY_RUN = "true"; await client.downloadArtifact( squirrelSimulatorArtifact.storedFile.downloadFilepath, @@ -332,8 +332,8 @@ describe('gcsApi module', () => { }); }); // end describe('download') - describe('listArtifactsForRevision', () => { - it('calls the GCS library getFiles method with the right parameters', async () => { + describe("listArtifactsForRevision", () => { + it("calls the GCS library getFiles method with the right parameters", async () => { expect.assertions(1); mockGCSGetFiles.mockReturnValue([[]]); @@ -353,7 +353,7 @@ describe('gcsApi module', () => { }); }); - it('converts GCSFile objects in response to RemoteArtifact objects', async () => { + it("converts GCSFile objects in response to RemoteArtifact objects", async () => { expect.assertions(1); mockGCSGetFiles.mockReturnValue([[squirrelStatsGCSFileObj]]); @@ -383,11 +383,11 @@ describe('gcsApi module', () => { expect(artifacts.length).toEqual(2); }); - it('errors if GCS file listing goes sideways', async () => { + it("errors if GCS file listing goes sideways", async () => { expect.assertions(1); mockGCSGetFiles.mockImplementation(() => { - throw new Error('The squirrel got away!'); + throw new Error("The squirrel got away!"); }); await expect( @@ -396,7 +396,7 @@ describe('gcsApi module', () => { squirrelRepo, squirrelSimulatorCommit ) - ).rejects.toThrowError('Error retrieving artifact list from GCS'); + ).rejects.toThrowError("Error retrieving artifact list from GCS"); }); }); // end describe('listArtifactsForRevision') }); // end describe('CraftGCSClient class') diff --git a/src/utils/__tests__/githubApi.test.ts b/src/utils/__tests__/githubApi.test.ts index 6277c8da..37a1547c 100644 --- a/src/utils/__tests__/githubApi.test.ts +++ b/src/utils/__tests__/githubApi.test.ts @@ -1,4 +1,4 @@ -import Github from '@octokit/rest'; +import Github from "@octokit/rest"; import { codeMatches, @@ -7,54 +7,54 @@ import { HTTP_RESPONSE_2XX, retryHttp, RetryParams, -} from '../githubApi'; +} from "../githubApi"; const mockRepos = { getContents: jest.fn(), }; // TODO rewrite with module mock, port github helpers from probot-release -jest.mock('@octokit/rest', () => +jest.mock("@octokit/rest", () => jest.fn().mockImplementation(() => ({ repos: mockRepos })) ); -describe('getFile', () => { +describe("getFile", () => { const github = new Github(); - const owner = 'owner'; - const repo = 'repo'; + const owner = "owner"; + const repo = "repo"; const getContents = (github.repos.getContents as unknown) as jest.Mock; - test('loads and decodes the file', async () => { + test("loads and decodes the file", async () => { expect.assertions(2); - const testContent = 'test content.'; + const testContent = "test content."; getContents.mockReturnValue({ - data: { content: Buffer.from(testContent).toString('base64') }, + data: { content: Buffer.from(testContent).toString("base64") }, }); const content = await getFile( github, owner, repo, - '/path/to/file', - 'v1.0.0' + "/path/to/file", + "v1.0.0" ); expect(getContents).toHaveBeenCalledWith({ - owner: 'owner', - path: '/path/to/file', - ref: 'v1.0.0', - repo: 'repo', + owner: "owner", + path: "/path/to/file", + ref: "v1.0.0", + repo: "repo", }); expect(content).toBe(testContent); }); - test('returns null for missing files', async () => { + test("returns null for missing files", async () => { expect.assertions(1); getContents.mockImplementation(() => { - const e = new Error('file not found') as any; + const e = new Error("file not found") as any; e.status = 404; throw e; }); @@ -63,16 +63,16 @@ describe('getFile', () => { github, owner, repo, - '/path/to/missing', - 'v1.0.0' + "/path/to/missing", + "v1.0.0" ); expect(content).toBe(undefined); }); - test('rejects all other errors', async () => { + test("rejects all other errors", async () => { expect.assertions(3); - const errorText = 'internal server error'; + const errorText = "internal server error"; getContents.mockImplementation(() => { const e = new Error(errorText) as any; e.status = 500; @@ -80,7 +80,7 @@ describe('getFile', () => { }); try { - await getFile(github, owner, repo, '/path/to/missing', 'v1.0.0'); + await getFile(github, owner, repo, "/path/to/missing", "v1.0.0"); } catch (e) { expect(e.message).toMatch(errorText); expect(e.status).toBe(500); @@ -89,25 +89,25 @@ describe('getFile', () => { }); }); -describe('codeMatches', () => { - test('accepts numerical code', () => { +describe("codeMatches", () => { + test("accepts numerical code", () => { expect(codeMatches(100, [100])).toBe(true); }); - test('accepts text code', () => { + test("accepts text code", () => { expect(codeMatches(101, [HTTP_RESPONSE_1XX])).toBe(true); }); - test('allows single value instead of a list', () => { + test("allows single value instead of a list", () => { expect(codeMatches(102, HTTP_RESPONSE_1XX)).toBe(true); }); - test('does not accept invalid code', () => { + test("does not accept invalid code", () => { expect(codeMatches(100, [200, HTTP_RESPONSE_2XX])).toBe(false); }); }); -describe('retryHttp', () => { +describe("retryHttp", () => { const params: Partial = { cooldown: 1 }; const errorCode = (c: number) => ({ status: c, @@ -115,14 +115,14 @@ describe('retryHttp', () => { // these are standing in for an async function (the type is () => // Promise) - const funcReturns = async () => Promise.resolve('result'); + const funcReturns = async () => Promise.resolve("result"); const funcThrows = async () => Promise.reject(errorCode(400)); - test('resolves without an error', async () => { - await expect(retryHttp(funcReturns, params)).resolves.toBe('result'); + test("resolves without an error", async () => { + await expect(retryHttp(funcReturns, params)).resolves.toBe("result"); }); - test('resolves after one retry', async () => { + test("resolves after one retry", async () => { const f = jest .fn() .mockImplementationOnce(funcThrows) @@ -130,10 +130,10 @@ describe('retryHttp', () => { expect( await retryHttp(f, { ...params, retryCodes: [400], retries: 1 }) - ).toBe('result'); + ).toBe("result"); }); - test('throws an error after max retries', async () => { + test("throws an error after max retries", async () => { expect.assertions(1); const f = jest .fn() @@ -143,13 +143,13 @@ describe('retryHttp', () => { try { await retryHttp(f, { ...params, retryCodes: [400], retries: 1 }); - throw Error('unreachable'); + throw Error("unreachable"); } catch (e) { return expect(e).toEqual(errorCode(400)); } }); - test('calls the cleanup function after each retry', async () => { + test("calls the cleanup function after each retry", async () => { const f = jest .fn() .mockImplementationOnce(funcThrows) @@ -167,11 +167,11 @@ describe('retryHttp', () => { retries: 2, retryCodes: [400], }) - ).toBe('result'); + ).toBe("result"); expect(cleanupCalled).toBe(2); }); - test('throws an error if error code is not in list', async () => { + test("throws an error if error code is not in list", async () => { expect.assertions(1); const f = jest .fn() @@ -180,7 +180,7 @@ describe('retryHttp', () => { try { await retryHttp(f, { ...params, retryCodes: [500] }); - throw Error('unreachable'); + throw Error("unreachable"); } catch (e) { return expect(e).toEqual(errorCode(400)); } diff --git a/src/utils/__tests__/helpers.test.ts b/src/utils/__tests__/helpers.test.ts index d7d18b79..d29c2eb6 100644 --- a/src/utils/__tests__/helpers.test.ts +++ b/src/utils/__tests__/helpers.test.ts @@ -1,6 +1,6 @@ -import { isDryRun } from '../helpers'; +import { isDryRun } from "../helpers"; -describe('isDryRun', () => { +describe("isDryRun", () => { /** * Helper function to test expected isDryRun() output given a DRY_RUN value * @@ -23,13 +23,13 @@ describe('isDryRun', () => { delete process.env.DRY_RUN; }); - test('undefined', () => testValue(undefined, false)); - test('empty string', () => testValue('', false)); - test('false', () => testValue('false', false)); - test('0', () => testValue('0', false)); - test('no', () => testValue('no', false)); - test('true', () => testValue('true', true)); - test('1', () => testValue('1', true)); - test('yes', () => testValue('yes', true)); - test('any non-empty string', () => testValue('dogs are great!', true)); + test("undefined", () => testValue(undefined, false)); + test("empty string", () => testValue("", false)); + test("false", () => testValue("false", false)); + test("0", () => testValue("0", false)); + test("no", () => testValue("no", false)); + test("true", () => testValue("true", true)); + test("1", () => testValue("1", true)); + test("yes", () => testValue("yes", true)); + test("any non-empty string", () => testValue("dogs are great!", true)); }); // end describe('isDryRun') diff --git a/src/utils/__tests__/noInput.test.ts b/src/utils/__tests__/noInput.test.ts index 517135dc..738489ae 100644 --- a/src/utils/__tests__/noInput.test.ts +++ b/src/utils/__tests__/noInput.test.ts @@ -1,48 +1,48 @@ /* eslint-env jest */ -import { hasInput, hasNoInput, resetNoInput, setNoInput } from '../noInput'; +import { hasInput, hasNoInput, resetNoInput, setNoInput } from "../noInput"; -describe('setNoInput', () => { +describe("setNoInput", () => { afterEach(() => { delete process.env.CI; delete process.env.CRAFT_NO_INPUT; resetNoInput(); }); - test('sets and returns true', () => { + test("sets and returns true", () => { setNoInput(true); expect(hasNoInput()).toBe(true); expect(hasInput()).toBe(false); }); - test('sets and returns false', () => { + test("sets and returns false", () => { setNoInput(false); expect(hasNoInput()).toBe(false); expect(hasInput()).toBe(true); }); }); -describe('resetNoInput', () => { +describe("resetNoInput", () => { afterEach(() => { delete process.env.CI; delete process.env.CRAFT_NO_INPUT; resetNoInput(); }); - test('sets noInput to false by default', () => { + test("sets noInput to false by default", () => { delete process.env.CRAFT_NO_INPUT; resetNoInput(); expect(hasNoInput()).toBe(false); }); - test('sets noInput to true via craft env', () => { - process.env.CRAFT_NO_INPUT = '1'; + test("sets noInput to true via craft env", () => { + process.env.CRAFT_NO_INPUT = "1"; resetNoInput(); expect(hasNoInput()).toBe(true); }); - test('sets noInput to true via CI env', () => { - process.env.CI = '1'; + test("sets noInput to true via CI env", () => { + process.env.CI = "1"; resetNoInput(); expect(hasNoInput()).toBe(true); }); diff --git a/src/utils/__tests__/objects.test.ts b/src/utils/__tests__/objects.test.ts index f3238561..d3bde1b3 100644 --- a/src/utils/__tests__/objects.test.ts +++ b/src/utils/__tests__/objects.test.ts @@ -1,8 +1,8 @@ -import { clearObjectProperties } from '../objects'; +import { clearObjectProperties } from "../objects"; -describe('clearObjectProperties', () => { - test('clears enumerable properties', () => { - const obj = { a: 1, test: 'hello', f: () => 0, o: { 1: 2 } }; +describe("clearObjectProperties", () => { + test("clears enumerable properties", () => { + const obj = { a: 1, test: "hello", f: () => 0, o: { 1: 2 } }; expect(clearObjectProperties(obj)).toEqual({}); expect(obj).toEqual({}); diff --git a/src/utils/__tests__/packagePath.test.ts b/src/utils/__tests__/packagePath.test.ts index d06f702c..e3400f9b 100644 --- a/src/utils/__tests__/packagePath.test.ts +++ b/src/utils/__tests__/packagePath.test.ts @@ -1,30 +1,30 @@ -import { parseCanonical } from '../packagePath'; +import { parseCanonical } from "../packagePath"; -describe('parseCanonical', () => { - test('parses valid cases properly', async () => { - expect(parseCanonical('pypi:sentry-sdk')).toEqual(['pypi', 'sentry-sdk']); - expect(parseCanonical('npm:@sentry/browser')).toEqual([ - 'npm', - '@sentry', - 'browser', +describe("parseCanonical", () => { + test("parses valid cases properly", async () => { + expect(parseCanonical("pypi:sentry-sdk")).toEqual(["pypi", "sentry-sdk"]); + expect(parseCanonical("npm:@sentry/browser")).toEqual([ + "npm", + "@sentry", + "browser", ]); - expect(parseCanonical('test-registry:a.1/b.2/c.3')).toEqual([ - 'test-registry', - 'a.1', - 'b.2', - 'c.3', + expect(parseCanonical("test-registry:a.1/b.2/c.3")).toEqual([ + "test-registry", + "a.1", + "b.2", + "c.3", ]); }); - test('allows colons as path separators', async () => { - expect(parseCanonical('maven:io.sentry:sentry')).toEqual([ - 'maven', - 'io.sentry', - 'sentry', + test("allows colons as path separators", async () => { + expect(parseCanonical("maven:io.sentry:sentry")).toEqual([ + "maven", + "io.sentry", + "sentry", ]); }); - test('throws an error for invalid canonical names', async () => { + test("throws an error for invalid canonical names", async () => { function expectRaisesError(name: string): void { try { parseCanonical(name); @@ -34,9 +34,9 @@ describe('parseCanonical', () => { } } - expectRaisesError('invalid'); - expectRaisesError('invalid:'); - expectRaisesError('a/b'); - expectRaisesError('registry:a/'); + expectRaisesError("invalid"); + expectRaisesError("invalid:"); + expectRaisesError("a/b"); + expectRaisesError("registry:a/"); }); }); diff --git a/src/utils/__tests__/strings.test.ts b/src/utils/__tests__/strings.test.ts index 717b8969..326c91a5 100644 --- a/src/utils/__tests__/strings.test.ts +++ b/src/utils/__tests__/strings.test.ts @@ -3,14 +3,14 @@ import { sanitizeObject, formatSize, formatJson, -} from '../strings'; +} from "../strings"; -describe('sanitizeObject', () => { - test('processes empty object', () => { +describe("sanitizeObject", () => { + test("processes empty object", () => { expect(sanitizeObject({})).toEqual({}); }); - test('throws an error if given non-object', () => { + test("throws an error if given non-object", () => { function expectRaisesError(value: any): void { try { sanitizeObject(value); @@ -20,77 +20,77 @@ describe('sanitizeObject', () => { } } expectRaisesError(123); - expectRaisesError('a'); + expectRaisesError("a"); expectRaisesError(null); }); - test('processes simple objects without changes', () => { + test("processes simple objects without changes", () => { expect(sanitizeObject({ 1: 2 })).toEqual({ 1: 2 }); }); - test('processes nested objects without changes', () => { - expect(sanitizeObject({ 1: { a: { 3: true } }, 2: 'b' })).toEqual({ + test("processes nested objects without changes", () => { + expect(sanitizeObject({ 1: { a: { 3: true } }, 2: "b" })).toEqual({ 1: { a: { 3: true } }, - 2: 'b', + 2: "b", }); }); - test('ignores function values', () => { + test("ignores function values", () => { expect(sanitizeObject({ f: () => true })).toEqual({}); }); - test('replaces null with undefined', () => { + test("replaces null with undefined", () => { expect(sanitizeObject({ 1: null })).toEqual({ 1: undefined }); }); - test('normalizes keys with dots', () => { - expect(sanitizeObject({ '1.2.3': 3 })).toEqual({ - '1.2.3': 3, - '1__2__3': 3, + test("normalizes keys with dots", () => { + expect(sanitizeObject({ "1.2.3": 3 })).toEqual({ + "1.2.3": 3, + "1__2__3": 3, }); }); }); -describe('renderTemplateSafe', () => { - test('renders basic template', () => { - expect(renderTemplateSafe('x{{ var }}', { var: 123 })).toBe('x123'); +describe("renderTemplateSafe", () => { + test("renders basic template", () => { + expect(renderTemplateSafe("x{{ var }}", { var: 123 })).toBe("x123"); }); - test('renders nested values', () => { - expect(renderTemplateSafe('x{{ var.d }}', { var: { d: 123 } })).toBe( - 'x123' + test("renders nested values", () => { + expect(renderTemplateSafe("x{{ var.d }}", { var: { d: 123 } })).toBe( + "x123" ); }); - test('renders nested values with dotted keys', () => { - expect(renderTemplateSafe('x{{ var.d__1 }}', { var: { 'd.1': 123 } })).toBe( - 'x123' + test("renders nested values with dotted keys", () => { + expect(renderTemplateSafe("x{{ var.d__1 }}", { var: { "d.1": 123 } })).toBe( + "x123" ); }); - test('does not render globals', () => { - expect(renderTemplateSafe('{{ process }}', {})).toBe(''); + test("does not render globals", () => { + expect(renderTemplateSafe("{{ process }}", {})).toBe(""); }); }); -describe('formatSize', () => { - test('formats byte sizes', () => { - expect(formatSize(123)).toBe('123 B'); +describe("formatSize", () => { + test("formats byte sizes", () => { + expect(formatSize(123)).toBe("123 B"); }); - test('formats kilobyte sizes', () => { - expect(formatSize(125952)).toBe('123.0 kB'); + test("formats kilobyte sizes", () => { + expect(formatSize(125952)).toBe("123.0 kB"); }); - test('formats megabyte sizes', () => { - expect(formatSize(1289748)).toBe('1.23 MB'); + test("formats megabyte sizes", () => { + expect(formatSize(1289748)).toBe("1.23 MB"); }); }); -describe('formatJson', () => { - test('formats an integer', () => { - expect(formatJson(123)).toBe('123'); +describe("formatJson", () => { + test("formats an integer", () => { + expect(formatJson(123)).toBe("123"); }); - test('formats an object', () => { - expect(formatJson({ int: 123, str: 'hello', array: [2, 3, 4] })).toBe( + test("formats an object", () => { + expect(formatJson({ int: 123, str: "hello", array: [2, 3, 4] })).toBe( `{ "int": 123, "str": "hello", @@ -102,9 +102,9 @@ describe('formatJson', () => { }` ); }); - test('serializes an error', () => { - const errorStr = formatJson(Error('oops')); - expect(errorStr).toContain('Error: oops'); - expect(errorStr).toContain('at Object'); + test("serializes an error", () => { + const errorStr = formatJson(Error("oops")); + expect(errorStr).toContain("Error: oops"); + expect(errorStr).toContain("at Object"); }); }); diff --git a/src/utils/__tests__/system.test.ts b/src/utils/__tests__/system.test.ts index c3fa8802..6d4d796e 100644 --- a/src/utils/__tests__/system.test.ts +++ b/src/utils/__tests__/system.test.ts @@ -1,7 +1,7 @@ -import * as fs from 'fs'; +import * as fs from "fs"; -import { logger } from '../../logger'; -import { withTempFile } from '../files'; +import { logger } from "../../logger"; +import { withTempFile } from "../files"; import { calculateChecksum, @@ -11,78 +11,78 @@ import { replaceEnvVariable, sleepAsync, spawnProcess, -} from '../system'; +} from "../system"; -jest.mock('../../logger'); +jest.mock("../../logger"); -describe('spawnProcess', () => { - test('resolves on success with standard output', async () => { +describe("spawnProcess", () => { + test("resolves on success with standard output", async () => { expect.assertions(1); const stdout = - (await spawnProcess(process.execPath, ['-p', '"test"'])) || ''; - expect(stdout.toString()).toBe('test\n'); + (await spawnProcess(process.execPath, ["-p", '"test"'])) || ""; + expect(stdout.toString()).toBe("test\n"); }); - test('rejects on non-zero exit code', async () => { + test("rejects on non-zero exit code", async () => { try { expect.assertions(2); - await spawnProcess('test', ['']); + await spawnProcess("test", [""]); } catch (e) { expect(e.code).toBe(1); expect(e.message).toMatch(/code 1/); } }); - test('rejects on error', async () => { + test("rejects on error", async () => { try { expect.assertions(1); - await spawnProcess('this_command_does_not_exist'); + await spawnProcess("this_command_does_not_exist"); } catch (e) { expect(e.message).toMatch(/ENOENT/); } }); - test('attaches args on error', async () => { + test("attaches args on error", async () => { try { expect.assertions(1); - await spawnProcess('test', ['x', 'y']); + await spawnProcess("test", ["x", "y"]); } catch (e) { - expect(e.args).toEqual(['x', 'y']); + expect(e.args).toEqual(["x", "y"]); } }); - test('attaches options on error', async () => { + test("attaches options on error", async () => { try { expect.assertions(1); - await spawnProcess('test', [], { cwd: '/tmp/' }); + await spawnProcess("test", [], { cwd: "/tmp/" }); } catch (e) { - expect(e.options.cwd).toEqual('/tmp/'); + expect(e.options.cwd).toEqual("/tmp/"); } }); - test('strips env from options on error', async () => { + test("strips env from options on error", async () => { try { expect.assertions(1); - await spawnProcess('test', [], { env: { x: '123', password: '456' } }); + await spawnProcess("test", [], { env: { x: "123", password: "456" } }); } catch (e) { expect(e.options.env).toBeUndefined(); } }); - test('does not write to output by default', async () => { + test("does not write to output by default", async () => { const mockedLogInfo = logger.info as jest.Mock; - await spawnProcess(process.execPath, ['-p', '"test-string"']); + await spawnProcess(process.execPath, ["-p", '"test-string"']); expect(mockedLogInfo).toHaveBeenCalledTimes(0); }); - test('writes to output if told so', async () => { + test("writes to output if told so", async () => { const mockedLogInfo = logger.info as jest.Mock; await spawnProcess( process.execPath, - ['-e', 'process.stdout.write("test-string")'], + ["-e", 'process.stdout.write("test-string")'], {}, { showStdout: true } ); @@ -92,8 +92,8 @@ describe('spawnProcess', () => { }); }); -describe('sleepAsync', () => { - test('sleeps for at least the given number of ms', async () => { +describe("sleepAsync", () => { + test("sleeps for at least the given number of ms", async () => { const sleepMs = 50; const timeStart = new Date().getTime(); await sleepAsync(sleepMs); @@ -104,86 +104,86 @@ describe('sleepAsync', () => { }); }); -describe('replaceEnvVariable', () => { - test('replaces a variable', async () => { - expect(replaceEnvVariable('${ENV_VAR}', { ENV_VAR: '123' })).toBe('123'); +describe("replaceEnvVariable", () => { + test("replaces a variable", async () => { + expect(replaceEnvVariable("${ENV_VAR}", { ENV_VAR: "123" })).toBe("123"); }); - test('does not replace a variable if there is no curly braces', async () => { - expect(replaceEnvVariable('$ENV_VAR', { ENV_VAR: '123' })).toBe('$ENV_VAR'); + test("does not replace a variable if there is no curly braces", async () => { + expect(replaceEnvVariable("$ENV_VAR", { ENV_VAR: "123" })).toBe("$ENV_VAR"); }); - test('replaces a non-existing environment variable with empty string', async () => { - expect(replaceEnvVariable('${ENV_VAR}', {})).toBe(''); + test("replaces a non-existing environment variable with empty string", async () => { + expect(replaceEnvVariable("${ENV_VAR}", {})).toBe(""); }); }); -describe('calculateChecksum', () => { - test('Default checksum on a basic file', async () => { +describe("calculateChecksum", () => { + test("Default checksum on a basic file", async () => { expect.assertions(1); - await withTempFile(async tmpFilePath => { - fs.writeFileSync(tmpFilePath, '\n'); + await withTempFile(async (tmpFilePath) => { + fs.writeFileSync(tmpFilePath, "\n"); const checksum = await calculateChecksum(tmpFilePath); expect(checksum).toBe( - '01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b' + "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b" ); }); }); - test('Base64-formatted checksum on a basic file', async () => { + test("Base64-formatted checksum on a basic file", async () => { expect.assertions(1); - await withTempFile(async tmpFilePath => { - fs.writeFileSync(tmpFilePath, '\n'); + await withTempFile(async (tmpFilePath) => { + fs.writeFileSync(tmpFilePath, "\n"); const checksum = await calculateChecksum(tmpFilePath, { format: HashOutputFormat.Base64, }); - expect(checksum).toBe('AbpHGcgLb+kRsJGnwFEktk7uzpZOCcBY74+YBdrKVGs='); + expect(checksum).toBe("AbpHGcgLb+kRsJGnwFEktk7uzpZOCcBY74+YBdrKVGs="); }); }); - test('Base64-formatted checksum with custom algorithm on a basic file', async () => { + test("Base64-formatted checksum with custom algorithm on a basic file", async () => { expect.assertions(1); - await withTempFile(async tmpFilePath => { - fs.writeFileSync(tmpFilePath, '\n'); + await withTempFile(async (tmpFilePath) => { + fs.writeFileSync(tmpFilePath, "\n"); const checksum = await calculateChecksum(tmpFilePath, { algorithm: HashAlgorithm.SHA384, format: HashOutputFormat.Base64, }); expect(checksum).toBe( - '7GZOiJ7WwbJ2PKz3iZ2Vt/NHNz65guUjQZ/uo6o2LYkbO/Al8pImelhUBJCReJw+' + "7GZOiJ7WwbJ2PKz3iZ2Vt/NHNz65guUjQZ/uo6o2LYkbO/Al8pImelhUBJCReJw+" ); }); }); }); -describe('isExecutableInPath', () => { - test('checks for existing executable', () => { - expect(hasExecutable('node')).toBe(true); +describe("isExecutableInPath", () => { + test("checks for existing executable", () => { + expect(hasExecutable("node")).toBe(true); }); - test('checks for non-existing executable', () => { - expect(hasExecutable('not-existing-executable')).toBe(false); + test("checks for non-existing executable", () => { + expect(hasExecutable("not-existing-executable")).toBe(false); }); - test('checks for existing executable using absolute path', () => { + test("checks for existing executable using absolute path", () => { expect(hasExecutable(`${process.cwd()}/node_modules/.bin/jest`)).toBe(true); }); - test('checks for non-existing executable using absolute path', () => { - expect(hasExecutable('/dev/null/non-existing-binary')).toBe(false); + test("checks for non-existing executable using absolute path", () => { + expect(hasExecutable("/dev/null/non-existing-binary")).toBe(false); }); - test('checks for existing executable using relative path', () => { - expect(hasExecutable('./node_modules/.bin/jest')).toBe(true); + test("checks for existing executable using relative path", () => { + expect(hasExecutable("./node_modules/.bin/jest")).toBe(true); }); - test('checks for non-existing executable using relative path', () => { - expect(hasExecutable('./bin/non-existing-binary')).toBe(false); + test("checks for non-existing executable using relative path", () => { + expect(hasExecutable("./bin/non-existing-binary")).toBe(false); }); }); diff --git a/src/utils/__tests__/version.test.ts b/src/utils/__tests__/version.test.ts index ef0275f5..5e63b49a 100644 --- a/src/utils/__tests__/version.test.ts +++ b/src/utils/__tests__/version.test.ts @@ -8,47 +8,47 @@ import { parseVersion, SemVer, versionGreaterOrEqualThan, -} from '../version'; +} from "../version"; -describe('getVersion', () => { - test('extracts a basic SemVer versions', () => { - expect(getVersion('1.0.0')).toBe('1.0.0'); +describe("getVersion", () => { + test("extracts a basic SemVer versions", () => { + expect(getVersion("1.0.0")).toBe("1.0.0"); }); test('extracts a SemVer version with leading "v"', () => { - expect(getVersion('v1.0.0')).toBe('1.0.0'); + expect(getVersion("v1.0.0")).toBe("1.0.0"); }); - test('extracts a SemVer version from text', () => { - expect(getVersion('1.0.0 (foobar)')).toBe('1.0.0'); + test("extracts a SemVer version from text", () => { + expect(getVersion("1.0.0 (foobar)")).toBe("1.0.0"); }); - test('extracts a SemVer, but ignores subpatch level', () => { - expect(getVersion('1.0.0.1')).toBe('1.0.0'); + test("extracts a SemVer, but ignores subpatch level", () => { + expect(getVersion("1.0.0.1")).toBe("1.0.0"); }); }); -describe('isValidVersion', () => { - test('accepts valid version', () => { - expect(isValidVersion('1.2.3')).toBe(true); +describe("isValidVersion", () => { + test("accepts valid version", () => { + expect(isValidVersion("1.2.3")).toBe(true); }); - test('accepts valid pre-release version', () => { - expect(isValidVersion('1.2.3-beta')).toBe(true); + test("accepts valid pre-release version", () => { + expect(isValidVersion("1.2.3-beta")).toBe(true); }); - test('accepts valid Python-style version', () => { - expect(isValidVersion('1.2.3rc1')).toBe(true); + test("accepts valid Python-style version", () => { + expect(isValidVersion("1.2.3rc1")).toBe(true); }); test('does not accept leading "v"', () => { - expect(isValidVersion('v1.2.3')).toBe(false); + expect(isValidVersion("v1.2.3")).toBe(false); }); }); -describe('parseVersion', () => { - test('parses a full SemVer version', () => { - expect(parseVersion('1.2.3')).toEqual({ +describe("parseVersion", () => { + test("parses a full SemVer version", () => { + expect(parseVersion("1.2.3")).toEqual({ major: 1, minor: 2, patch: 3, @@ -56,87 +56,87 @@ describe('parseVersion', () => { }); test('parses a SemVer with leading "v"', () => { - expect(parseVersion('v1.2.3')).toEqual({ + expect(parseVersion("v1.2.3")).toEqual({ major: 1, minor: 2, patch: 3, }); }); - test('parses a pre-release SemVer', () => { - expect(parseVersion('v1.2.3-beta')).toEqual({ + test("parses a pre-release SemVer", () => { + expect(parseVersion("v1.2.3-beta")).toEqual({ major: 1, minor: 2, patch: 3, - pre: 'beta', + pre: "beta", }); }); - test('parses a complicated pre-release SemVer', () => { - expect(parseVersion('v1.2.3-beta.1')).toEqual({ + test("parses a complicated pre-release SemVer", () => { + expect(parseVersion("v1.2.3-beta.1")).toEqual({ major: 1, minor: 2, patch: 3, - pre: 'beta.1', + pre: "beta.1", }); }); - test('parses a SemVer with build metadata', () => { - expect(parseVersion('v1.2.3+linux')).toEqual({ - build: 'linux', + test("parses a SemVer with build metadata", () => { + expect(parseVersion("v1.2.3+linux")).toEqual({ + build: "linux", major: 1, minor: 2, patch: 3, }); }); - test('parses a pre-release SemVer with build metadata', () => { - expect(parseVersion('v1.2.3-beta+linux')).toEqual({ - build: 'linux', + test("parses a pre-release SemVer with build metadata", () => { + expect(parseVersion("v1.2.3-beta+linux")).toEqual({ + build: "linux", major: 1, minor: 2, patch: 3, - pre: 'beta', + pre: "beta", }); }); - test('parses a Python-style version', () => { - expect(parseVersion('v11.22.33rc1')).toEqual({ + test("parses a Python-style version", () => { + expect(parseVersion("v11.22.33rc1")).toEqual({ major: 11, minor: 22, patch: 33, - pre: 'rc1', + pre: "rc1", }); }); - test('does not parse an invalid version', () => { - expect(parseVersion('v1.2')).toBeNull(); + test("does not parse an invalid version", () => { + expect(parseVersion("v1.2")).toBeNull(); }); - test('cannot parse empty value', () => { - expect(parseVersion('')).toBeNull(); + test("cannot parse empty value", () => { + expect(parseVersion("")).toBeNull(); }); }); -describe('isPreviewRelease', () => { - test('accepts semver preview release', () => { - expect(isPreviewRelease('2.3.4-preview1')).toBe(true); +describe("isPreviewRelease", () => { + test("accepts semver preview release", () => { + expect(isPreviewRelease("2.3.4-preview1")).toBe(true); }); - test('accepts Python-style preview release', () => { - expect(isPreviewRelease('2.3.4rc0')).toBe(true); + test("accepts Python-style preview release", () => { + expect(isPreviewRelease("2.3.4rc0")).toBe(true); }); - test('does not accept non-preview release', () => { - expect(isPreviewRelease('2.3.4')).toBe(false); + test("does not accept non-preview release", () => { + expect(isPreviewRelease("2.3.4")).toBe(false); }); - test('does not accept non-release strings', () => { - expect(isPreviewRelease('4-preview')).toBe(false); + test("does not accept non-release strings", () => { + expect(isPreviewRelease("4-preview")).toBe(false); }); }); -describe('versionGreaterOrEqualThan', () => { +describe("versionGreaterOrEqualThan", () => { function semVerFactory( major: number, minor: number, @@ -147,57 +147,57 @@ describe('versionGreaterOrEqualThan', () => { return { major, minor, patch, pre, build }; } - test('compares different patch versions', () => { + test("compares different patch versions", () => { const v1 = semVerFactory(1, 2, 3); const v2 = semVerFactory(1, 2, 2); expect(versionGreaterOrEqualThan(v1, v2)).toBe(true); expect(versionGreaterOrEqualThan(v2, v1)).toBe(false); }); - test('compares different major versions', () => { + test("compares different major versions", () => { const v1 = semVerFactory(2, 0, 0); const v2 = semVerFactory(3, 0, 0); expect(versionGreaterOrEqualThan(v1, v2)).toBe(false); expect(versionGreaterOrEqualThan(v2, v1)).toBe(true); }); - test('compares different major versions', () => { + test("compares different major versions", () => { const v1 = semVerFactory(3, 1, 0); const v2 = semVerFactory(3, 0, 1); expect(versionGreaterOrEqualThan(v1, v2)).toBe(true); expect(versionGreaterOrEqualThan(v2, v1)).toBe(false); }); - test('equals true for equal versions', () => { + test("equals true for equal versions", () => { const v1 = semVerFactory(0, 1, 2); const v2 = semVerFactory(0, 1, 2); expect(versionGreaterOrEqualThan(v1, v2)).toBe(true); }); - test('prefers versions with pre-release parts', () => { - const v1 = semVerFactory(0, 1, 2, 'rc0'); + test("prefers versions with pre-release parts", () => { + const v1 = semVerFactory(0, 1, 2, "rc0"); const v2 = semVerFactory(0, 1, 2); expect(versionGreaterOrEqualThan(v1, v2)).toBe(false); expect(versionGreaterOrEqualThan(v2, v1)).toBe(true); }); - test('throws an exception if there are build parts', () => { - const v1 = semVerFactory(0, 1, 2, undefined, 'build123'); + test("throws an exception if there are build parts", () => { + const v1 = semVerFactory(0, 1, 2, undefined, "build123"); const v2 = semVerFactory(0, 1, 2); expect(() => versionGreaterOrEqualThan(v1, v2)).toThrowError(); expect(() => versionGreaterOrEqualThan(v2, v1)).toThrowError(); }); }); -describe('getPackage', () => { - test('reads package.json', () => { +describe("getPackage", () => { + test("reads package.json", () => { const pkg = getPackage(); - expect(pkg.name).toBe('@sentry/craft'); + expect(pkg.name).toBe("@sentry/craft"); }); }); -describe('getPackageVersion', () => { - test('reads package.json', () => { +describe("getPackageVersion", () => { + test("reads package.json", () => { const version = getPackage().version; expect(isValidVersion(version)).toBe(true); }); diff --git a/src/utils/async.ts b/src/utils/async.ts index 1624e5a2..f347b445 100644 --- a/src/utils/async.ts +++ b/src/utils/async.ts @@ -1,5 +1,5 @@ -import * as _ from 'lodash'; -import { reportError } from './errors'; +import * as _ from "lodash"; +import { reportError } from "./errors"; /** * Asynchronously calls the predicate on every element of the array and filters diff --git a/src/utils/awsLambdaLayerManager.ts b/src/utils/awsLambdaLayerManager.ts index 18856856..52ede14e 100644 --- a/src/utils/awsLambdaLayerManager.ts +++ b/src/utils/awsLambdaLayerManager.ts @@ -1,13 +1,13 @@ -import { DescribeRegionsCommandOutput, EC2 } from '@aws-sdk/client-ec2'; -import { Lambda } from '@aws-sdk/client-lambda'; -import { logger as loggerRaw } from '../logger'; +import { DescribeRegionsCommandOutput, EC2 } from "@aws-sdk/client-ec2"; +import { Lambda } from "@aws-sdk/client-lambda"; +import { logger as loggerRaw } from "../logger"; -const logger = loggerRaw.withScope('[aws-lambda-layer]'); +const logger = loggerRaw.withScope("[aws-lambda-layer]"); /** Prefix of the canonical name. */ -const RUNTIME_CANONICAL_PREFIX = 'aws-layer:'; +const RUNTIME_CANONICAL_PREFIX = "aws-layer:"; /** Substring used to separate the different ARN parts. */ -const ARN_SEPARATOR = ':'; +const ARN_SEPARATOR = ":"; /** Index (0-based) of the account number in the ARN. */ const ARN_ACCOUNT_INDEX = 4; @@ -79,9 +79,9 @@ export class AwsLambdaLayerManager { await lambda.addLayerVersionPermission({ LayerName: this.layerName, VersionNumber: publishedLayer.Version, - StatementId: 'public', - Action: 'lambda:GetLayerVersion', - Principal: '*', + StatementId: "public", + Action: "lambda:GetLayerVersion", + Principal: "*", }); if (this.verboseInfo) { @@ -91,7 +91,7 @@ export class AwsLambdaLayerManager { return { region: region, - arn: publishedLayer.LayerVersionArn || '', + arn: publishedLayer.LayerVersionArn || "", version: publishedLayer.Version || -1, }; } @@ -103,19 +103,19 @@ export class AwsLambdaLayerManager { */ public async publishToAllRegions(): Promise { const publishedLayers = await Promise.all( - this.awsRegions.map(async region => { + this.awsRegions.map(async (region) => { try { return await this.publishLayerToRegion(region); } catch (error) { logger.warn( - 'Something went wrong with AWS trying to publish to region ' + + "Something went wrong with AWS trying to publish to region " + `${region}: ${error.message}` ); return undefined; } }) ); - return publishedLayers.filter(layer => { + return publishedLayers.filter((layer) => { return layer !== undefined; }) as PublishedLayer[]; } @@ -135,15 +135,13 @@ export class AwsLambdaLayerManager { * regions) to AWS. For more information, see * https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/EC2.html#describeRegions-property */ -export async function getRegionsFromAws(): Promise< - DescribeRegionsCommandOutput -> { - logger.debug('Fetching AWS regions...'); - const ec2 = new EC2({ region: 'us-east-2' }); +export async function getRegionsFromAws(): Promise { + logger.debug("Fetching AWS regions..."); + const ec2 = new EC2({ region: "us-east-2" }); try { return await ec2.describeRegions({}); } catch (error) { - throw new Error('AWS error fetching regions.'); + throw new Error("AWS error fetching regions."); } } @@ -155,7 +153,7 @@ export function extractRegionNames( awsRegions: DescribeRegionsCommandOutput ): string[] { const regionNames: string[] = []; - awsRegions.Regions?.map(currentRegion => { + awsRegions.Regions?.map((currentRegion) => { if (currentRegion.RegionName !== undefined) { regionNames.push(currentRegion.RegionName); } diff --git a/src/utils/changes.ts b/src/utils/changes.ts index 10b40e48..b247f862 100644 --- a/src/utils/changes.ts +++ b/src/utils/changes.ts @@ -1,11 +1,11 @@ -import { getVersion } from './version'; +import { getVersion } from "./version"; /** * Path to the changelog file in the target repository */ -export const DEFAULT_CHANGELOG_PATH = 'CHANGELOG.md'; -export const DEFAULT_UNRELEASED_TITLE = 'Unreleased'; -const DEFAULT_CHANGESET_BODY = '- No documented changes.'; +export const DEFAULT_CHANGELOG_PATH = "CHANGELOG.md"; +export const DEFAULT_UNRELEASED_TITLE = "Unreleased"; +const DEFAULT_CHANGESET_BODY = "- No documented changes."; /** * A single changeset with name and description @@ -42,7 +42,7 @@ function extractChangeset(markdown: string, location: ChangesetLoc): Changeset { const end = location.end ? location.end.index : undefined; const body = markdown.substring(start, end).trim(); const name = (location.start[2] || location.start[3]) - .replace(/\(.*\)$/, '') + .replace(/\(.*\)$/, "") .trim(); return { name, body }; } @@ -108,12 +108,12 @@ export function findChangeset( let changesetLoc = locateChangeset( markdown, - match => getVersion(match) === version + (match) => getVersion(match) === version ); if (!changesetLoc && fallbackToUnreleased) { changesetLoc = locateChangeset( markdown, - match => match === DEFAULT_UNRELEASED_TITLE + (match) => match === DEFAULT_UNRELEASED_TITLE ); } @@ -127,7 +127,7 @@ export function findChangeset( * @returns The markdown string without the changeset with the provided header */ export function removeChangeset(markdown: string, header: string): string { - const location = locateChangeset(markdown, match => match === header); + const location = locateChangeset(markdown, (match) => match === header); if (!location) { return markdown; } @@ -155,11 +155,11 @@ export function prependChangeset( // Try to locate the top-most non-empty header, no matter what is inside const start = locateChangeset(markdown, Boolean)?.start; const padding = start?.[1]?.length || 0; - const padStr = new Array(padding + 1).join(' '); + const padStr = new Array(padding + 1).join(" "); const body = changeset.body || `${padStr}${DEFAULT_CHANGESET_BODY}`; let header; if (start?.[3]) { - const underline = new Array(changeset.name.length + 1).join('-'); + const underline = new Array(changeset.name.length + 1).join("-"); header = `${changeset.name}\n${underline}`; } else { header = `## ${changeset.name}`; diff --git a/src/utils/checksum.ts b/src/utils/checksum.ts index 5e7229f3..067b500a 100644 --- a/src/utils/checksum.ts +++ b/src/utils/checksum.ts @@ -1,9 +1,9 @@ import { BaseArtifactProvider, RemoteArtifact, -} from '../artifact_providers/base'; -import { ConfigurationError } from './errors'; -import { HashAlgorithm, HashOutputFormat } from './system'; +} from "../artifact_providers/base"; +import { ConfigurationError } from "./errors"; +import { HashAlgorithm, HashOutputFormat } from "./system"; /** Describes a checksum entry. */ export interface ChecksumEntry { @@ -31,7 +31,7 @@ export function castChecksums(checksums: any[]): ChecksumEntry[] { } return checksums.map( (item: any): ChecksumEntry => { - if (typeof item !== 'object' || !item.algorithm || !item.format) { + if (typeof item !== "object" || !item.algorithm || !item.format) { throw new ConfigurationError( `Invalid checksum type: ${JSON.stringify(item)}` ); diff --git a/src/utils/env.ts b/src/utils/env.ts index 41180d90..7185a6a5 100644 --- a/src/utils/env.ts +++ b/src/utils/env.ts @@ -1,15 +1,15 @@ -import { existsSync, statSync } from 'fs'; -import { join } from 'path'; -const os = require('os'); +import { existsSync, statSync } from "fs"; +import { join } from "path"; +const os = require("os"); -import nvar from 'nvar'; +import nvar from "nvar"; -import { CONFIG_FILE_NAME, getConfigFileDir } from '../config'; -import { ConfigurationError } from './errors'; -import { logger } from '../logger'; +import { CONFIG_FILE_NAME, getConfigFileDir } from "../config"; +import { ConfigurationError } from "./errors"; +import { logger } from "../logger"; /** File name where additional environment variables are stored */ -export const ENV_FILE_NAME = '.craft.env'; +export const ENV_FILE_NAME = ".craft.env"; /** * A token, key, or other value which can be stored either in an env file or @@ -169,7 +169,7 @@ export function readEnvironmentConfig(overwriteExisting = false): void { * only one is required. */ export function checkEnvForPrerequisite(...varList: RequiredConfigVar[]): void { - const varNames = varList.map(v => v.name).join(' or '); + const varNames = varList.map((v) => v.name).join(" or "); logger.debug(`Checking for environment variable(s) ${varNames}`); if (!varList.some(envHasVar)) { diff --git a/src/utils/errors.ts b/src/utils/errors.ts index c5e2a59a..676217ac 100644 --- a/src/utils/errors.ts +++ b/src/utils/errors.ts @@ -1,6 +1,6 @@ -import { logger } from '../logger'; -import { isDryRun } from './helpers'; -import { captureException } from '@sentry/node'; +import { logger } from "../logger"; +import { isDryRun } from "./helpers"; +import { captureException } from "@sentry/node"; /** * Custom error class that describes client configuration errors @@ -39,7 +39,7 @@ export function reportError( throw errorObj; } else { // conversely, convert the error to a string if it isn't already one - const errorStr = typeof error === 'string' ? error : String(error); + const errorStr = typeof error === "string" ? error : String(error); errorLogger.error(`[dry-run] ${errorStr}`); } } @@ -56,14 +56,14 @@ export function reportError( export function coerceType( obj: T, typeName: - | 'string' - | 'number' - | 'bigint' - | 'boolean' - | 'symbol' - | 'undefined' - | 'object' - | 'function', + | "string" + | "number" + | "bigint" + | "boolean" + | "symbol" + | "undefined" + | "object" + | "function", message?: string ): T | never { const objType = typeof obj; diff --git a/src/utils/files.ts b/src/utils/files.ts index 55e04132..3b13f1ba 100644 --- a/src/utils/files.ts +++ b/src/utils/files.ts @@ -1,11 +1,11 @@ -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; -import rimraf from 'rimraf'; -import * as tmp from 'tmp'; -import * as util from 'util'; +import * as fs from "fs"; +import * as os from "os"; +import * as path from "path"; +import rimraf from "rimraf"; +import * as tmp from "tmp"; +import * as util from "util"; -import { filterAsync } from './async'; +import { filterAsync } from "./async"; const lstat = util.promisify(fs.lstat); const readdirp = util.promisify(fs.readdir); @@ -54,8 +54,8 @@ export async function scan( */ export async function listFiles(directory: string): Promise { const files = await readdir(directory); - const paths = files.map(name => path.join(directory, name)); - return filterAsync(paths, async filePath => { + const paths = files.map((name) => path.join(directory, name)); + return filterAsync(paths, async (filePath) => { const stats = await lstat(filePath); return stats.isFile(); }); @@ -75,7 +75,7 @@ export async function listFiles(directory: string): Promise { export async function withTempDir( callback: (arg: string) => T | Promise, cleanup = true, - prefix = 'craft-' + prefix = "craft-" ): Promise { const directory = await mkdtemp(path.join(os.tmpdir(), prefix)); try { @@ -108,7 +108,7 @@ export async function withTempDir( export async function withTempFile( callback: (arg: string) => T | Promise, cleanup = true, - prefix = 'craft-' + prefix = "craft-" ): Promise { tmp.setGracefulCleanup(); const tmpFile = tmp.fileSync({ prefix }); @@ -130,8 +130,8 @@ export async function withTempFile( */ export function detectContentType(artifactName: string): string | undefined { const extensionToType: Array<[RegExp, string]> = [ - [/\.js$/, 'application/javascript; charset=utf-8'], - [/\.js\.map$/, 'application/json; charset=utf-8'], + [/\.js$/, "application/javascript; charset=utf-8"], + [/\.js\.map$/, "application/json; charset=utf-8"], ]; for (const entry of extensionToType) { const [regex, contentType] = entry; diff --git a/src/utils/filters.ts b/src/utils/filters.ts index 72dc9d0b..ed51f825 100644 --- a/src/utils/filters.ts +++ b/src/utils/filters.ts @@ -15,8 +15,8 @@ * @returns Regular expression object that was created from the string */ export function stringToRegexp(str: string): RegExp { - const firstSlash = str.indexOf('/'); - const lastSlash = str.lastIndexOf('/'); + const firstSlash = str.indexOf("/"); + const lastSlash = str.lastIndexOf("/"); if (firstSlash !== 0 || lastSlash < 2) { throw new TypeError(`Invalid RegExp string specified: ${str}`); } diff --git a/src/utils/gcsApi.ts b/src/utils/gcsApi.ts index b3e35a36..fe79bd24 100644 --- a/src/utils/gcsApi.ts +++ b/src/utils/gcsApi.ts @@ -1,20 +1,20 @@ -import * as fs from 'fs'; -import * as path from 'path'; +import * as fs from "fs"; +import * as path from "path"; import { Bucket as GCSBucket, File as GCSFile, Storage as GCSStorage, UploadOptions as GCSUploadOptions, -} from '@google-cloud/storage'; -import { isDryRun } from './helpers'; +} from "@google-cloud/storage"; +import { isDryRun } from "./helpers"; -import { logger, Logger, logger as loggerRaw } from '../logger'; -import { reportError, ConfigurationError } from './errors'; -import { checkEnvForPrerequisite, RequiredConfigVar } from './env'; -import { detectContentType } from './files'; -import { RemoteArtifact } from '../artifact_providers/base'; -import { formatJson } from './strings'; +import { logger, Logger, logger as loggerRaw } from "../logger"; +import { reportError, ConfigurationError } from "./errors"; +import { checkEnvForPrerequisite, RequiredConfigVar } from "./env"; +import { detectContentType } from "./files"; +import { RemoteArtifact } from "../artifact_providers/base"; +import { formatJson } from "./strings"; const DEFAULT_MAX_RETRIES = 5; export const DEFAULT_UPLOAD_METADATA = { cacheControl: `public, max-age=300` }; @@ -121,7 +121,7 @@ export function getGCSCredsFromEnv( reportError(`Error parsing JSON credentials: ${err}`); } - for (const field of ['project_id', 'client_email', 'private_key']) { + for (const field of ["project_id", "client_email", "private_key"]) { if (!parsedCofig[field]) { reportError(`GCS credentials missing \`${field}\`!`); } @@ -181,7 +181,7 @@ export class CraftGCSClient { // stopped normalizing paths. If you keep this, you'll end up with a path // like `//your/dir/and/file` instead of `/your/dir/and/file` // See #169 for more information. - if (pathInBucket[0] === '/') { + if (pathInBucket[0] === "/") { pathInBucket = pathInBucket.substring(1); } @@ -243,7 +243,7 @@ export class CraftGCSClient { this.logger.debug( `Successfully uploaded \`${filename}\`. It can be downloaded by running ` + `\`gsutil cp ${path.posix.join( - 'gs://', + "gs://", this.bucketName, pathInBucket, filename @@ -356,6 +356,6 @@ export class CraftGCSClient { } const files = filesResponse[0]; - return files.map(gcsFile => this.convertToRemoteArtifact(gcsFile)); + return files.map((gcsFile) => this.convertToRemoteArtifact(gcsFile)); } } diff --git a/src/utils/githubApi.ts b/src/utils/githubApi.ts index 349b2012..759e816d 100644 --- a/src/utils/githubApi.ts +++ b/src/utils/githubApi.ts @@ -1,12 +1,12 @@ -import Github from '@octokit/rest'; -import request from 'request'; -import { Duplex, Readable } from 'stream'; +import Github from "@octokit/rest"; +import request from "request"; +import { Duplex, Readable } from "stream"; -import { LOG_LEVEL, logger } from '../logger'; +import { LOG_LEVEL, logger } from "../logger"; -import { ConfigurationError } from './errors'; -import { isDryRun } from './helpers'; -import { sleepAsync } from './system'; +import { ConfigurationError } from "./errors"; +import { isDryRun } from "./helpers"; +import { sleepAsync } from "./system"; export const HTTP_UNPROCESSABLE_ENTITY = 422; export const HTTP_RESPONSE_1XX = /^1\d\d$/; @@ -53,9 +53,9 @@ export class GithubRemote { /** GitHub personal authentication token */ protected apiToken?: string; /** GitHub hostname */ - protected readonly GITHUB_HOSTNAME: string = 'github.com'; + protected readonly GITHUB_HOSTNAME: string = "github.com"; /** Protocol prefix */ - protected readonly PROTOCOL_PREFIX: string = 'https://'; + protected readonly PROTOCOL_PREFIX: string = "https://"; /** Url in the form of /OWNER/REPO/ */ protected readonly url: string; @@ -102,7 +102,7 @@ export class GithubRemote { const authData = this.username && this.apiToken ? `${this.username}:${this.apiToken}@` - : ''; + : ""; return this.PROTOCOL_PREFIX + authData + this.GITHUB_HOSTNAME + this.url; } } @@ -117,7 +117,7 @@ export function getGithubApiToken(): string { process.env.GITHUB_TOKEN || process.env.GITHUB_API_TOKEN; if (!githubApiToken) { throw new ConfigurationError( - 'GitHub target: GITHUB_TOKEN not found in the environment' + "GitHub target: GITHUB_TOKEN not found in the environment" ); } return githubApiToken; @@ -131,7 +131,7 @@ export function getGithubApiToken(): string { * @param token Github authentication token * @returns Github client */ -export function getGithubClient(token = ''): Github { +export function getGithubClient(token = ""): Github { const githubApiToken = token || getGithubApiToken(); const attrs = { @@ -147,7 +147,7 @@ export function getGithubClient(token = ''): Github { } // eslint-disable-next-line @typescript-eslint/no-var-requires - const { retry } = require('@octokit/plugin-retry'); + const { retry } = require("@octokit/plugin-retry"); const octokitWithRetries = Github.plugin(retry); return new octokitWithRetries(attrs); } @@ -162,7 +162,7 @@ export async function getAuthUsername(github: Github): Promise { const userData = await github.users.getAuthenticated({}); const username = (userData.data || {}).login; if (!username) { - throw new Error('Cannot reliably detect Github username, aborting'); + throw new Error("Cannot reliably detect Github username, aborting"); } return username; } @@ -195,7 +195,7 @@ export async function getFile( if (response.data instanceof Array || response.data.content === undefined) { return undefined; } - return Buffer.from(response.data.content, 'base64').toString(); + return Buffer.from(response.data.content, "base64").toString(); } catch (e) { if (e.status === 404) { return undefined; @@ -240,14 +240,14 @@ export async function mergeReleaseBranch( ): Promise { const baseBranch = base || (await getDefaultBranch(github, owner, repo)); if (!baseBranch) { - throw new Error('Cannot determine base branch while merging'); + throw new Error("Cannot determine base branch while merging"); } try { logger.info(`Merging release branch: "${branch}" into "${baseBranch}"...`); if (isDryRun()) { - logger.info('[dry-run] Skipping merge.'); + logger.info("[dry-run] Skipping merge."); return undefined; } @@ -261,7 +261,7 @@ export async function mergeReleaseBranch( logger.info(`Merging: done.`); return response.data.sha; } else if (response.status === 204) { - logger.warn('Base already contains the head, nothing to merge'); + logger.warn("Base already contains the head, nothing to merge"); return undefined; } else { throw new Error(`Unexpected response: ${JSON.stringify(response)}`); @@ -271,7 +271,7 @@ export async function mergeReleaseBranch( // Conflicts found logger.error( `Cannot merge release branch "${branch}": conflicts detected`, - 'Please resolve the conflicts and merge the branch manually:', + "Please resolve the conflicts and merge the branch manually:", ` git checkout master && git merge ${branch}` ); } @@ -334,7 +334,7 @@ export function codeMatches( } for (const pattern of patternList) { - if (typeof pattern === 'number') { + if (typeof pattern === "number") { if (pattern === code) { return true; } diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index 068debb9..3e47400b 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -7,6 +7,6 @@ export function isDryRun(): boolean { const dryRun = process.env.DRY_RUN; return ( - Boolean(dryRun) && dryRun !== 'false' && dryRun !== '0' && dryRun !== 'no' + Boolean(dryRun) && dryRun !== "false" && dryRun !== "0" && dryRun !== "no" ); } diff --git a/src/utils/noInput.ts b/src/utils/noInput.ts index 3ff6dae7..506e393d 100644 --- a/src/utils/noInput.ts +++ b/src/utils/noInput.ts @@ -33,7 +33,7 @@ export function setNoInput(val: boolean): void { * a true-ish value. */ export function resetNoInput(): void { - const envVal = process.env.CRAFT_NO_INPUT || process.env.CI || ''; + const envVal = process.env.CRAFT_NO_INPUT || process.env.CI || ""; noInput = - envVal === '0' || envVal.toLowerCase() === 'false' ? false : !!envVal; + envVal === "0" || envVal.toLowerCase() === "false" ? false : !!envVal; } diff --git a/src/utils/packagePath.ts b/src/utils/packagePath.ts index cdb0047f..ee7bee57 100644 --- a/src/utils/packagePath.ts +++ b/src/utils/packagePath.ts @@ -1,6 +1,6 @@ -import * as path from 'path'; -import { RegistryPackageType } from '../targets/registry'; -import { ConfigurationError } from './errors'; +import * as path from "path"; +import { RegistryPackageType } from "../targets/registry"; +import { ConfigurationError } from "./errors"; /** * Returns the path to the SDK, given its canonical name. @@ -11,7 +11,7 @@ import { ConfigurationError } from './errors'; */ function getSdkPackagePath(registryDir: string, canonical: string): string { const packageDirs = parseCanonical(canonical); - return path.posix.join(registryDir, 'packages', ...packageDirs); + return path.posix.join(registryDir, "packages", ...packageDirs); } /** @@ -23,12 +23,12 @@ function getSdkPackagePath(registryDir: string, canonical: string): string { */ function getAppPackagePath(registryDir: string, canonical: string): string { const packageDirs = parseCanonical(canonical); - if (packageDirs[0] !== 'app') { + if (packageDirs[0] !== "app") { throw new ConfigurationError( `Invalid canonical entry for an app: ${canonical}` ); } - return path.posix.join(registryDir, 'apps', ...packageDirs.slice(1)); + return path.posix.join(registryDir, "apps", ...packageDirs.slice(1)); } /** @@ -67,19 +67,19 @@ export function getPackageDirPath( * @returns A list of directories */ export function parseCanonical(canonicalName: string): string[] { - const [registry, ...splitPackageName] = canonicalName.split(':'); + const [registry, ...splitPackageName] = canonicalName.split(":"); // This essentially replaces colons with forward slashes for the package name // of the initial canonical name - const packageName = splitPackageName.join('/'); + const packageName = splitPackageName.join("/"); if (!registry || !packageName) { throw new ConfigurationError( `Cannot parse canonical name for the package: ${canonicalName}` ); } - const packageDirs = packageName.split('/'); - if (packageDirs.some(x => !x)) { + const packageDirs = packageName.split("/"); + if (packageDirs.some((x) => !x)) { throw new ConfigurationError( `Cannot parse canonical name for the package: ${canonicalName}` ); diff --git a/src/utils/registry.ts b/src/utils/registry.ts index d1032dec..e74e2581 100644 --- a/src/utils/registry.ts +++ b/src/utils/registry.ts @@ -1,10 +1,10 @@ -import * as fs from 'fs'; -import * as path from 'path'; +import * as fs from "fs"; +import * as path from "path"; -import { logger } from '../logger'; -import { createSymlinks } from './symlink'; -import { reportError } from './errors'; -import { GithubRemote } from './githubApi'; +import { logger } from "../logger"; +import { createSymlinks } from "./symlink"; +import { reportError } from "./errors"; +import { GithubRemote } from "./githubApi"; /** * Gets the package manifest version in the given directory. @@ -20,7 +20,7 @@ export async function getPackageManifest( if (fs.existsSync(versionFilePath)) { reportError(`Version file for "${version}" already exists. Aborting.`); } - const packageManifestPath = path.join(packageDirPath, 'latest.json'); + const packageManifestPath = path.join(packageDirPath, "latest.json"); logger.debug('Reading the current configuration from "latest.json"...'); return JSON.parse(fs.readFileSync(packageManifestPath).toString()) || {}; } @@ -40,8 +40,8 @@ export function updateManifestSymlinks( versionFilePath: string, previousVersion: string ): void { - const manifestString = JSON.stringify(updatedManifest, undefined, 2) + '\n'; - logger.debug('Updated manifest', manifestString); + const manifestString = JSON.stringify(updatedManifest, undefined, 2) + "\n"; + logger.debug("Updated manifest", manifestString); logger.debug(`Writing updated manifest to "${versionFilePath}"...`); fs.writeFileSync(versionFilePath, manifestString); createSymlinks(versionFilePath, version, previousVersion); @@ -51,5 +51,5 @@ export function updateManifestSymlinks( * Returns a GithubRemote object to the sentry release registry. */ export function getRegistryGithubRemote(): GithubRemote { - return new GithubRemote('getsentry', 'sentry-release-registry'); + return new GithubRemote("getsentry", "sentry-release-registry"); } diff --git a/src/utils/sentry.ts b/src/utils/sentry.ts index 3d9a0a38..3f26c5b7 100644 --- a/src/utils/sentry.ts +++ b/src/utils/sentry.ts @@ -1,35 +1,35 @@ -import { arch, hostname, platform, release, userInfo } from 'os'; +import { arch, hostname, platform, release, userInfo } from "os"; -import * as Sentry from '@sentry/node'; +import * as Sentry from "@sentry/node"; -import { logger } from '../logger'; -import { getPackageVersion } from './version'; +import { logger } from "../logger"; +import { getPackageVersion } from "./version"; /** * Initializes Sentry SDK if CRAFT_SENTRY_SDN is set */ export function initSentrySdk(): void { - const sentryDsn = (process.env.CRAFT_SENTRY_DSN || '').trim(); - if (!sentryDsn.startsWith('http')) { + const sentryDsn = (process.env.CRAFT_SENTRY_DSN || "").trim(); + if (!sentryDsn.startsWith("http")) { logger.debug( - 'Not initializing Sentry SDK - no valid DSN found in environment or ' + - 'config files' + "Not initializing Sentry SDK - no valid DSN found in environment or " + + "config files" ); return; } - logger.debug('Sentry DSN found in the environment, initializing the SDK'); + logger.debug("Sentry DSN found in the environment, initializing the SDK"); Sentry.init({ dsn: sentryDsn }); - Sentry.configureScope(scope => { - scope.setTag('os-username', userInfo().username); - scope.setTag('os-hostname', hostname()); - scope.setTag('os-platform', platform()); - scope.setTag('os-arch', arch()); - scope.setTag('os-release', release()); + Sentry.configureScope((scope) => { + scope.setTag("os-username", userInfo().username); + scope.setTag("os-hostname", hostname()); + scope.setTag("os-platform", platform()); + scope.setTag("os-arch", arch()); + scope.setTag("os-release", release()); - scope.setExtra('argv', process.argv); - scope.setExtra('craft-version', getPackageVersion()); - scope.setExtra('working-directory', process.cwd()); + scope.setExtra("argv", process.argv); + scope.setExtra("craft-version", getPackageVersion()); + scope.setExtra("working-directory", process.cwd()); }); } diff --git a/src/utils/strings.ts b/src/utils/strings.ts index 2eadeef7..79863cd4 100644 --- a/src/utils/strings.ts +++ b/src/utils/strings.ts @@ -1,5 +1,5 @@ -import * as mustache from 'mustache'; -import * as util from 'util'; +import * as mustache from "mustache"; +import * as util from "util"; /** * Sanitizes object attributes @@ -12,7 +12,7 @@ import * as util from 'util'; * @returns Normalized object */ export function sanitizeObject(obj: Record): any { - if (typeof obj !== 'object' || obj === null) { + if (typeof obj !== "object" || obj === null) { throw new Error(`Cannot normalize value: ${obj}`); } @@ -23,17 +23,17 @@ export function sanitizeObject(obj: Record): any { let newValue; // Allowed value types - if (['boolean', 'string', 'number', 'undefined'].indexOf(valueType) > -1) { + if (["boolean", "string", "number", "undefined"].indexOf(valueType) > -1) { newValue = value; } else if (value === null) { newValue = undefined; - } else if (valueType === 'object') { + } else if (valueType === "object") { newValue = sanitizeObject(value); } else { continue; } result[key] = newValue; - const normalizedKey = key.replace(/\./g, '__'); + const normalizedKey = key.replace(/\./g, "__"); if (key !== normalizedKey) { result[normalizedKey] = newValue; } @@ -84,7 +84,7 @@ export function formatSize(size: number): string { // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export function formatJson(obj: any): string { const result = JSON.stringify(obj, null, 4); - if (obj instanceof Error && result === '{}') { + if (obj instanceof Error && result === "{}") { // Error that doesn't implement toJSON() return util.format(obj); } else { diff --git a/src/utils/symlink.ts b/src/utils/symlink.ts index feae5e08..299ce5bd 100644 --- a/src/utils/symlink.ts +++ b/src/utils/symlink.ts @@ -1,9 +1,9 @@ -import * as fs from 'fs'; -import * as path from 'path'; +import * as fs from "fs"; +import * as path from "path"; -import { logger } from '../logger'; -import { ConfigurationError } from './errors'; -import { parseVersion, versionGreaterOrEqualThan } from './version'; +import { logger } from "../logger"; +import { ConfigurationError } from "./errors"; +import { parseVersion, versionGreaterOrEqualThan } from "./version"; /** * Creates a symlink, overwriting the existing one @@ -54,7 +54,7 @@ export function createSymlinks( logger.debug( `Changing symlink for "latest.json" from version "${oldVersion}" to "${newVersion}"` ); - forceSymlink(baseVersionName, path.join(packageDir, 'latest.json')); + forceSymlink(baseVersionName, path.join(packageDir, "latest.json")); } // link major diff --git a/src/utils/system.ts b/src/utils/system.ts index cd0627a4..15b3a4b5 100644 --- a/src/utils/system.ts +++ b/src/utils/system.ts @@ -1,28 +1,28 @@ -import { spawn, SpawnOptions } from 'child_process'; -import { createHash, Hash } from 'crypto'; -import * as fs from 'fs'; -import * as path from 'path'; -import split from 'split'; -import { Readable } from 'stream'; -import tar from 'tar'; -import unzipper from 'unzipper'; +import { spawn, SpawnOptions } from "child_process"; +import { createHash, Hash } from "crypto"; +import * as fs from "fs"; +import * as path from "path"; +import split from "split"; +import { Readable } from "stream"; +import tar from "tar"; +import unzipper from "unzipper"; -import { logger } from '../logger'; +import { logger } from "../logger"; -import { reportError } from './errors'; -import { downloadSources } from './githubApi'; -import { isDryRun } from './helpers'; +import { reportError } from "./errors"; +import { downloadSources } from "./githubApi"; +import { isDryRun } from "./helpers"; /** * Types of supported hashing algorithms */ export enum HashAlgorithm { /** SHA256 */ - SHA256 = 'sha256', + SHA256 = "sha256", /** SHA384 */ - SHA384 = 'sha384', + SHA384 = "sha384", /** SHA512 */ - SHA512 = 'sha512', + SHA512 = "sha512", } /** @@ -30,9 +30,9 @@ export enum HashAlgorithm { */ export enum HashOutputFormat { /** Hex digest, consists of [0-9a-f] characters */ - Hex = 'hex', + Hex = "hex", /** The digest is encoded as base64 string. Used e.g. for Subresource Integrity (SRI) */ - Base64 = 'base64', + Base64 = "base64", } /** @@ -87,14 +87,14 @@ export function replaceEnvVariable( arg: string, env: Record ): string { - if (!env || !arg || arg[0] !== '$') { + if (!env || !arg || arg[0] !== "$") { return arg; } const argLen = arg.length; - if (arg[1] === '{' && arg[argLen - 1] === '}') { + if (arg[1] === "{" && arg[argLen - 1] === "}") { const envVarKey = arg.slice(2, argLen - 1); - return env[envVarKey] || ''; + return env[envVarKey] || ""; } else { return arg; } @@ -132,17 +132,17 @@ export async function spawnProcess( options: SpawnOptions = {}, spawnProcessOptions: SpawnProcessOptions = {} ): Promise { - const argsString = args.map(arg => `"${arg}"`).join(' '); + const argsString = args.map((arg) => `"${arg}"`).join(" "); if (isDryRun() && !spawnProcessOptions.enableInDryRunMode) { - logger.info('[dry-run] Not spawning process:', `${command} ${argsString}`); + logger.info("[dry-run] Not spawning process:", `${command} ${argsString}`); return undefined; } return new Promise((resolve, reject) => { const stdoutChunks: Buffer[] = []; - let stdout = ''; - let stderr = ''; + let stdout = ""; + let stderr = ""; let child; // NOTE: On Linux, stdout and stderr might flush immediately after the @@ -154,26 +154,26 @@ export async function spawnProcess( reject(processError(e.code, command, args, options, stdout, stderr)); try { - logger.debug('Spawning process:', `${command} ${argsString}`); + logger.debug("Spawning process:", `${command} ${argsString}`); // Do a shell-like replacement of arguments that look like environment variables - const processedArgs = args.map(arg => + const processedArgs = args.map((arg) => replaceEnvVariable(arg, { ...process.env, ...options.env }) ); // Allow child to accept input - options.stdio = ['inherit', 'pipe', 'pipe']; + options.stdio = ["inherit", "pipe", "pipe"]; child = spawn(command, processedArgs, options); if (!child.stdout || !child.stderr) { - throw new Error('Invalid standard output or error for child process'); + throw new Error("Invalid standard output or error for child process"); } - child.on('exit', code => (code === 0 ? succeed() : fail({ code }))); - child.on('error', fail); + child.on("exit", (code) => (code === 0 ? succeed() : fail({ code }))); + child.on("error", fail); - child.stdout.on('data', (chunk: Buffer) => stdoutChunks.push(chunk)); + child.stdout.on("data", (chunk: Buffer) => stdoutChunks.push(chunk)); - child.stdout.pipe(split()).on('data', (data: any) => { + child.stdout.pipe(split()).on("data", (data: any) => { const output = `${command}: ${data}`; if (spawnProcessOptions.showStdout) { logger.info(output); @@ -182,7 +182,7 @@ export async function spawnProcess( } stdout += `${output}\n`; }); - child.stderr.pipe(split()).on('data', (data: any) => { + child.stderr.pipe(split()).on("data", (data: any) => { const output = `${command}: ${data}`; logger.debug(output); stderr += `${output}\n`; @@ -216,9 +216,9 @@ export async function calculateChecksum( const hash = createHash(algorithm); return new Promise((resolve, reject) => { - stream.on('data', data => hash.update(data, 'utf8')); - stream.on('end', () => resolve(formatDigest(hash, format))); - stream.on('error', reject); + stream.on("data", (data) => hash.update(data, "utf8")); + stream.on("end", () => resolve(formatDigest(hash, format))); + stream.on("error", reject); }); } @@ -232,10 +232,10 @@ export async function calculateChecksum( function formatDigest(hash: Hash, format: HashOutputFormat): string { switch (format) { case HashOutputFormat.Base64: { - return hash.digest('base64'); + return hash.digest("base64"); } case HashOutputFormat.Hex: { - return hash.digest('hex'); + return hash.digest("hex"); } default: { throw new Error(`Invalid hash format: ${format}`); @@ -249,7 +249,7 @@ function formatDigest(hash: Hash, format: HashOutputFormat): string { * @param ms Milliseconds to sleep */ export async function sleepAsync(ms: number): Promise { - return new Promise(resolve => setTimeout(resolve, ms)); + return new Promise((resolve) => setTimeout(resolve, ms)); } /** @@ -258,13 +258,15 @@ export async function sleepAsync(ms: number): Promise { * @param fileName Base name of the given file */ function getPotentialPaths(fileName: string): string[] { - const envPath = process.env.PATH || ''; - const envExt = process.env.PATHEXT || ''; + const envPath = process.env.PATH || ""; + const envExt = process.env.PATHEXT || ""; return envPath - .replace(/"/g, '') + .replace(/"/g, "") .split(path.delimiter) - .map(chunk => - envExt.split(path.delimiter).map(ext => path.join(chunk, fileName + ext)) + .map((chunk) => + envExt + .split(path.delimiter) + .map((ext) => path.join(chunk, fileName + ext)) ) .reduce((a, b) => a.concat(b)); } @@ -295,7 +297,7 @@ function isExecutable(filePath: string): boolean { */ export function hasExecutable(name: string): boolean { // Relative/absolute path - if (name.indexOf('/') > -1) { + if (name.indexOf("/") > -1) { return isExecutable(name); } const found = getPotentialPaths(name).find(isExecutable) || []; @@ -333,8 +335,8 @@ export async function extractSourcesFromTarStream( try { stream .pipe(tar.extract({ strip: 1, cwd: dir })) - .on('error', reject) - .on('finish', () => { + .on("error", reject) + .on("finish", () => { setTimeout(resolve, 100); }); } catch (e) { @@ -359,8 +361,8 @@ export async function extractZipArchive( try { fs.createReadStream(filePath) .pipe(unzipper.Extract({ strip: 1, path: dir })) - .on('error', reject) - .on('finish', () => { + .on("error", reject) + .on("finish", () => { setTimeout(resolve, 100); }); } catch (e) { @@ -400,15 +402,15 @@ export async function downloadAndExtract( * @param maxTimeDiff Maximum time interval in milliseconds between the signals */ export function catchKeyboardInterrupt(maxTimeDiff = 1000): void { - if (process.env.CRAFT_CATCH_KEYBOARD_INTERRUPT !== '1') { + if (process.env.CRAFT_CATCH_KEYBOARD_INTERRUPT !== "1") { logger.debug( - 'Catching Ctrl-C is disabled by default. See https://github.com/getsentry/craft/issues/21' + "Catching Ctrl-C is disabled by default. See https://github.com/getsentry/craft/issues/21" ); return; } if (!process.stdin.isTTY || !process.stdout.isTTY) { - logger.debug('stdin or stdout is not a TTY, not catching SIGINTs'); + logger.debug("stdin or stdout is not a TTY, not catching SIGINTs"); return; } @@ -417,20 +419,20 @@ export function catchKeyboardInterrupt(maxTimeDiff = 1000): void { // the external "yarn" process is killed, and no longer attached to stdout, // while the craft process receives only one SIGINT. // Hence, we're trying to detect if we run the script via yarn/npm. - if ((process.env.npm_package_scripts_cli || '').indexOf('node') > -1) { - logger.debug('NPM/Yarn script environment detected, not catching SIGINTs'); + if ((process.env.npm_package_scripts_cli || "").indexOf("node") > -1) { + logger.debug("NPM/Yarn script environment detected, not catching SIGINTs"); return; } - logger.debug('Setting custom SIGINT handler'); + logger.debug("Setting custom SIGINT handler"); let lastSignalTime = 0; - process.on('SIGINT', () => { + process.on("SIGINT", () => { const now = Date.now(); if (lastSignalTime && now - lastSignalTime <= maxTimeDiff) { - logger.warn('Got ^C, exiting.'); + logger.warn("Got ^C, exiting."); process.exit(1); } else { - logger.warn('Press ^C again (quickly!) to exit.'); + logger.warn("Press ^C again (quickly!) to exit."); lastSignalTime = now; } }); diff --git a/src/utils/version.ts b/src/utils/version.ts index 9b4e32b9..d164469c 100644 --- a/src/utils/version.ts +++ b/src/utils/version.ts @@ -1,4 +1,4 @@ -import { getGitTagPrefix } from '../config'; +import { getGitTagPrefix } from "../config"; /** * Regular expression for matching semver versions @@ -23,7 +23,7 @@ const semverRegex = () => export function getVersion(text: string): string | null { const matches = semverRegex().exec(text); const version = matches && matches[0]; - return version && version[0].toLowerCase() === 'v' + return version && version[0].toLowerCase() === "v" ? version.substr(1) : version; } @@ -137,10 +137,10 @@ export function versionToTag(version: string, tagPrefix?: string): string { * Reads "package.json" from project root and returns its contents */ export function getPackage(): any { - const pkg = require('../../package.json') || {}; + const pkg = require("../../package.json") || {}; // Sanity check if (Object.keys(pkg).length === 0) { - throw new Error('Invalid package.json: the file is empty!'); + throw new Error("Invalid package.json: the file is empty!"); } return pkg; } diff --git a/tsconfig.build.json b/tsconfig.build.json index 362a9f45..1142f69b 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,9 +1,7 @@ { "extends": "@sentry/typescript/tsconfig.json", "compilerOptions": { - "lib": [ - "es2018" - ], + "lib": ["es2018"], "target": "es2018", "skipLibCheck": true, "forceConsistentCasingInFileNames": true, @@ -17,9 +15,5 @@ "noEmitHelpers": false }, "include": ["src/**/*.ts"], - "exclude": [ - "dist/**/*", - "**/__mocks__/**", - "**/__tests__/**" - ] + "exclude": ["dist/**/*", "**/__mocks__/**", "**/__tests__/**"] } diff --git a/tsconfig.json b/tsconfig.json index 96f03886..a3299ca3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,12 +4,6 @@ "types": ["node", "jest"], "plugins": [] }, - "include": [ - "src/**/*.ts", - "**/__mocks__/**/*.ts", - "**/__tests_/**/*.ts" - ], - "exclude": [ - "dist/**/*" - ] + "include": ["src/**/*.ts", "**/__mocks__/**/*.ts", "**/__tests_/**/*.ts"], + "exclude": ["dist/**/*"] } From 6a7f65a81a151cf483042597508d6d6353527c38 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 3 May 2021 11:10:42 +0300 Subject: [PATCH 07/14] enable single-quote in prettier options --- .prettierrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.prettierrc b/.prettierrc index 0967ef42..de3b9062 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1 +1 @@ -{} +{"singleQuote": true} From 71ab3f09d2e8dd54c4d9342cc367d7cb834d19c3 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 3 May 2021 11:11:15 +0300 Subject: [PATCH 08/14] fix bot-email --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 0bfd4b0d..9b1b820b 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -23,7 +23,7 @@ jobs: run: yarn lint - name: Save lint fixes run: > - git config user.email "bot@getsentry.com" && + git config user.email "bot@sentry.io" && git config user.name "getsentry-bot" && git diff --quiet || git commit -anm 'ref: Lint fixes' && From 637dcac1d4dd687eadc9414bf74df425906220cc Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 3 May 2021 11:12:51 +0300 Subject: [PATCH 09/14] run lint --- .craft.yml | 10 +- .eslintrc.js | 18 +- .github/workflows/build.yml | 6 +- .github/workflows/lint.yml | 2 +- .github/workflows/release.yml | 2 +- .prettierrc | 2 +- README.md | 12 +- action.yml | 18 +- cloudbuild.yaml | 44 ++--- docs/_site/assets/main.css | 4 +- docs/_site/assets/normalize.css | 14 +- jest.config.js | 8 +- scripts/config-json-schema-to-ts.js | 12 +- src/__mocks__/@aws-sdk/client-lambda.ts | 2 +- src/__mocks__/fs.ts | 2 +- src/__mocks__/logger.ts | 4 +- src/__tests__/config.test.ts | 40 ++-- src/__tests__/index.test.ts | 2 +- src/artifact_providers/base.ts | 12 +- src/artifact_providers/gcs.ts | 14 +- src/artifact_providers/github.ts | 32 +-- src/artifact_providers/none.ts | 6 +- src/artifact_providers/zeus.ts | 22 +-- src/commands/__tests__/prepare.test.ts | 28 +-- src/commands/__tests__/publish.test.ts | 32 +-- src/commands/artifacts.ts | 22 +-- src/commands/artifacts_cmds/download.ts | 54 ++--- src/commands/artifacts_cmds/list.ts | 24 +-- src/commands/prepare.ts | 136 ++++++------- src/commands/publish.ts | 186 +++++++++--------- src/commands/targets.ts | 10 +- src/config.ts | 68 +++---- src/index.ts | 50 ++--- src/logger.ts | 10 +- src/schemas/projectConfig.schema.ts | 134 ++++++------- src/schemas/project_config.ts | 18 +- src/status_providers/base.ts | 22 +-- src/status_providers/github.ts | 44 ++--- src/status_providers/zeus.ts | 6 +- src/stores/__tests__/zeus.test.ts | 74 +++---- src/stores/zeus.ts | 18 +- src/targets/__tests__/awsLambda.test.ts | 66 +++---- src/targets/__tests__/crates.test.ts | 36 ++-- src/targets/__tests__/index.test.ts | 16 +- src/targets/awsLambdaLayer.ts | 86 ++++---- src/targets/base.ts | 16 +- src/targets/brew.ts | 46 ++--- src/targets/cocoapods.ts | 46 ++--- src/targets/crates.ts | 70 +++---- src/targets/docker.ts | 40 ++-- src/targets/gcs.ts | 44 ++--- src/targets/gem.ts | 26 +-- src/targets/ghPages.ts | 64 +++--- src/targets/github.ts | 60 +++--- src/targets/index.ts | 40 ++-- src/targets/npm.ts | 74 +++---- src/targets/nuget.ts | 36 ++-- src/targets/pypi.ts | 28 +-- src/targets/registry.ts | 84 ++++---- src/types/consola.d.ts | 2 +- src/types/mustache.d.ts | 2 +- src/types/nvar.ts | 2 +- src/types/split.d.ts | 2 +- src/types/unzipper.ts | 2 +- src/utils/__fixtures__/gcsApi.ts | 56 +++--- src/utils/__fixtures__/gcsFileObj.ts | 138 ++++++------- src/utils/__tests__/async.test.ts | 90 ++++----- .../__tests__/awsLambdaLayerManager.test.ts | 56 +++--- src/utils/__tests__/changes.test.ts | 110 +++++------ src/utils/__tests__/env.test.ts | 170 ++++++++-------- src/utils/__tests__/errors.test.ts | 22 +-- src/utils/__tests__/files.test.ts | 52 ++--- src/utils/__tests__/filters.test.ts | 28 +-- src/utils/__tests__/gcsAPI.test.ts | 130 ++++++------ src/utils/__tests__/githubApi.test.ts | 78 ++++---- src/utils/__tests__/helpers.test.ts | 22 +-- src/utils/__tests__/noInput.test.ts | 20 +- src/utils/__tests__/objects.test.ts | 8 +- src/utils/__tests__/packagePath.test.ts | 46 ++--- src/utils/__tests__/strings.test.ts | 84 ++++---- src/utils/__tests__/system.test.ts | 112 +++++------ src/utils/__tests__/version.test.ts | 128 ++++++------ src/utils/async.ts | 4 +- src/utils/awsLambdaLayerManager.ts | 28 +-- src/utils/changes.ts | 14 +- src/utils/checksum.ts | 8 +- src/utils/env.ts | 18 +- src/utils/errors.ts | 24 +-- src/utils/files.ts | 22 +-- src/utils/filters.ts | 4 +- src/utils/gcsApi.ts | 26 +-- src/utils/githubApi.ts | 40 ++-- src/utils/helpers.ts | 2 +- src/utils/noInput.ts | 4 +- src/utils/packagePath.ts | 18 +- src/utils/registry.ts | 20 +- src/utils/sentry.ts | 34 ++-- src/utils/strings.ts | 14 +- src/utils/symlink.ts | 12 +- src/utils/system.ts | 108 +++++----- src/utils/version.ts | 8 +- 101 files changed, 1935 insertions(+), 1935 deletions(-) diff --git a/.craft.yml b/.craft.yml index f791c243..b2be7983 100644 --- a/.craft.yml +++ b/.craft.yml @@ -1,4 +1,4 @@ -minVersion: "0.21.0" +minVersion: '0.21.0' github: owner: getsentry repo: craft @@ -14,18 +14,18 @@ targets: paths: - path: /craft/{{version}}/ metadata: - cacheControl: "public, max-age=2592000" + cacheControl: 'public, max-age=2592000' - path: /craft/latest/ metadata: - cacheControl: "public, max-age=300" + cacheControl: 'public, max-age=300' - name: registry type: app - urlTemplate: "https://downloads.sentry-cdn.com/craft/{{version}}/{{file}}" + urlTemplate: 'https://downloads.sentry-cdn.com/craft/{{version}}/{{file}}' checksums: - algorithm: sha256 format: hex config: - canonical: "app:craft" + canonical: 'app:craft' - name: docker source: us.gcr.io/sentryio/craft target: getsentry/craft diff --git a/.eslintrc.js b/.eslintrc.js index 6efc033a..4f3853a3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,18 +4,18 @@ module.exports = { es2017: true, node: true, }, - parser: "@typescript-eslint/parser", - plugins: ["@typescript-eslint"], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], extends: [ - "prettier", - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "prettier/@typescript-eslint", + 'prettier', + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'prettier/@typescript-eslint', ], rules: { - "@typescript-eslint/no-explicit-any": "off", - "no-constant-condition": ["error", { checkLoops: false }], + '@typescript-eslint/no-explicit-any': 'off', + 'no-constant-condition': ['error', { checkLoops: false }], // Make sure variables marked with _ are ignored (ex. _varName) - "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], + '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], }, }; diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ee7ed997..a6151816 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: "Build / Test / Artifacts" +name: 'Build / Test / Artifacts' on: push: branches: @@ -11,13 +11,13 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: ["10", "12", "14", "16"] + node: ['10', '12', '14', '16'] name: Node ${{ matrix.node }} steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: "${{ matrix.node }}" + node-version: '${{ matrix.node }}' - uses: actions/cache@v2 id: cache with: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 9b1b820b..f3208d36 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,4 +1,4 @@ -name: "Lint" +name: 'Lint' on: pull_request: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 32e5654e..d5f923b3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ on: jobs: release: runs-on: ubuntu-latest - name: "Release a new version" + name: 'Release a new version' steps: - uses: actions/checkout@v2 with: diff --git a/.prettierrc b/.prettierrc index de3b9062..63778788 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1 +1 @@ -{"singleQuote": true} +{ "singleQuote": true } diff --git a/README.md b/README.md index bbaba12d..dcf57a13 100644 --- a/README.md +++ b/README.md @@ -354,7 +354,7 @@ your configuration. **Example:** ```yaml -minVersion: "0.5.0" +minVersion: '0.5.0' ``` ### Required Files @@ -434,13 +434,13 @@ targets: - algorithm: sha384 format: base64 config: - canonical: "npm:@sentry/browser" + canonical: 'npm:@sentry/browser' - name: registry id: node type: sdk onlyIfPresent: /^sentry-node-.*\.tgz$/ config: - canonical: "npm:@sentry/node" + canonical: 'npm:@sentry/node' ``` ### Per-target options @@ -783,13 +783,13 @@ targets: - name: registry type: sdk config: - canonical: "npm:@sentry/browser" + canonical: 'npm:@sentry/browser' - name: registry type: app - urlTemplate: "https://example.com/{{version}}/{{file}}" + urlTemplate: 'https://example.com/{{version}}/{{file}}' config: - canonical: "npm:@sentry/browser" + canonical: 'npm:@sentry/browser' checksums: - algorithm: sha256 format: hex diff --git a/action.yml b/action.yml index ab31f28d..f0752f33 100644 --- a/action.yml +++ b/action.yml @@ -1,22 +1,22 @@ -name: "Craft" -description: "Use getsentry/craft to publish your project" +name: 'Craft' +description: 'Use getsentry/craft to publish your project' inputs: action: - description: "The action to take. Can be either prepare or publish" + description: 'The action to take. Can be either prepare or publish' required: true - default: "--help" + default: '--help' version: - description: "The version number for the new release" + description: 'The version number for the new release' required: true no_merge: - description: "Do not merge the release branch after publishing" + description: 'Do not merge the release branch after publishing' required: false keep_branch: - description: "Do not remove release branch after merging it" + description: 'Do not remove release branch after merging it' required: false runs: - using: "docker" - image: "docker://getsentry/craft" + using: 'docker' + image: 'docker://getsentry/craft' args: - ${{ inputs.action }} - ${{ inputs.version }} diff --git a/cloudbuild.yaml b/cloudbuild.yaml index dea4f163..ac8e2159 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -1,33 +1,33 @@ steps: - - name: "gcr.io/kaniko-project/executor:v1.5.1" + - name: 'gcr.io/kaniko-project/executor:v1.5.1' args: - - "--cache=true" - - "--use-new-run" - - "--build-arg" - - "SOURCE_COMMIT=$COMMIT_SHA" - - "--destination=us.gcr.io/$PROJECT_ID/craft:builder-$COMMIT_SHA" - - "-f" - - "builder.dockerfile" - - name: "us.gcr.io/$PROJECT_ID/craft:builder-$COMMIT_SHA" - - name: "gcr.io/kaniko-project/executor:v1.5.1" + - '--cache=true' + - '--use-new-run' + - '--build-arg' + - 'SOURCE_COMMIT=$COMMIT_SHA' + - '--destination=us.gcr.io/$PROJECT_ID/craft:builder-$COMMIT_SHA' + - '-f' + - 'builder.dockerfile' + - name: 'us.gcr.io/$PROJECT_ID/craft:builder-$COMMIT_SHA' + - name: 'gcr.io/kaniko-project/executor:v1.5.1' args: - - "--cache=true" - - "--use-new-run" - - "--build-arg" - - "SOURCE_COMMIT=$COMMIT_SHA" - - "--destination=us.gcr.io/$PROJECT_ID/craft:$COMMIT_SHA" + - '--cache=true' + - '--use-new-run' + - '--build-arg' + - 'SOURCE_COMMIT=$COMMIT_SHA' + - '--destination=us.gcr.io/$PROJECT_ID/craft:$COMMIT_SHA' timeout: 900s # Smoke tests - - name: "us.gcr.io/$PROJECT_ID/craft:$COMMIT_SHA" + - name: 'us.gcr.io/$PROJECT_ID/craft:$COMMIT_SHA' args: - - "--help" + - '--help' timeout: 60s - - name: "gcr.io/cloud-builders/docker" - secretEnv: ["DOCKER_PASSWORD"] - entrypoint: "bash" + - name: 'gcr.io/cloud-builders/docker' + secretEnv: ['DOCKER_PASSWORD'] + entrypoint: 'bash' args: - - "-e" - - "-c" + - '-e' + - '-c' - | # Only push to Docker Hub from master [ "$BRANCH_NAME" != "master" ] && exit 0 diff --git a/docs/_site/assets/main.css b/docs/_site/assets/main.css index 443df7af..84804805 100644 --- a/docs/_site/assets/main.css +++ b/docs/_site/assets/main.css @@ -1,5 +1,5 @@ body { - font-family: "Oxygen", serif; + font-family: 'Oxygen', serif; color: #46433a; background-color: #fcfcfc; } @@ -113,7 +113,7 @@ footer { } .poweredby { - font-family: "Arial Narrow", Arial; + font-family: 'Arial Narrow', Arial; font-size: 0.6em; line-height: 0.6em; padding: 0 5px; diff --git a/docs/_site/assets/normalize.css b/docs/_site/assets/normalize.css index 458eea1e..d9f54fd9 100644 --- a/docs/_site/assets/normalize.css +++ b/docs/_site/assets/normalize.css @@ -331,8 +331,8 @@ input { * 2. Remove excess padding in IE 8/9/10. */ -input[type="checkbox"], -input[type="radio"] { +input[type='checkbox'], +input[type='radio'] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } @@ -343,8 +343,8 @@ input[type="radio"] { * decrement button to change from `default` to `text`. */ -input[type="number"]::-webkit-inner-spin-button, -input[type="number"]::-webkit-outer-spin-button { +input[type='number']::-webkit-inner-spin-button, +input[type='number']::-webkit-outer-spin-button { height: auto; } @@ -354,7 +354,7 @@ input[type="number"]::-webkit-outer-spin-button { * (include `-moz` to future-proof). */ -input[type="search"] { +input[type='search'] { -webkit-appearance: textfield; /* 1 */ -moz-box-sizing: content-box; -webkit-box-sizing: content-box; /* 2 */ @@ -367,8 +367,8 @@ input[type="search"] { * padding (and `textfield` appearance). */ -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { +input[type='search']::-webkit-search-cancel-button, +input[type='search']::-webkit-search-decoration { -webkit-appearance: none; } diff --git a/jest.config.js b/jest.config.js index 03706c4f..79317ff0 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,6 @@ module.exports = { - preset: "ts-jest", - testEnvironment: "node", - testPathIgnorePatterns: ["/dist/", "/node_modules/"], - modulePathIgnorePatterns: ["/dist/"], + preset: 'ts-jest', + testEnvironment: 'node', + testPathIgnorePatterns: ['/dist/', '/node_modules/'], + modulePathIgnorePatterns: ['/dist/'], }; diff --git a/scripts/config-json-schema-to-ts.js b/scripts/config-json-schema-to-ts.js index 14bd13f2..4e4688c7 100644 --- a/scripts/config-json-schema-to-ts.js +++ b/scripts/config-json-schema-to-ts.js @@ -1,19 +1,19 @@ /** * Convert JSON schema for project configuration to a set of TypeScript interfaces */ -const fs = require("fs"); -const json2ts = require("json-schema-to-typescript"); +const fs = require('fs'); +const json2ts = require('json-schema-to-typescript'); process.chdir(__dirname); -const jsonInputPath = "../src/schemas/projectConfig.schema.ts"; -const tsOutputPath = "../src/schemas/project_config.ts"; +const jsonInputPath = '../src/schemas/projectConfig.schema.ts'; +const tsOutputPath = '../src/schemas/project_config.ts'; // FIXME Duplicates compilation options in config.test.ts -const compileOptions = { style: { singleQuote: true, trailingComma: "es5" } }; +const compileOptions = { style: { singleQuote: true, trailingComma: 'es5' } }; const schema = require(jsonInputPath); json2ts - .compile(schema, "", compileOptions) + .compile(schema, '', compileOptions) .then((ts) => fs.writeFileSync(tsOutputPath, ts)) .catch((e) => console.error(e)); diff --git a/src/__mocks__/@aws-sdk/client-lambda.ts b/src/__mocks__/@aws-sdk/client-lambda.ts index 8404599a..64c88b50 100644 --- a/src/__mocks__/@aws-sdk/client-lambda.ts +++ b/src/__mocks__/@aws-sdk/client-lambda.ts @@ -2,7 +2,7 @@ const PUBLISHED_LAYER_TEST = { Version: 1, - LayerVersionArn: "test:layer:version:arn", + LayerVersionArn: 'test:layer:version:arn', }; export class Lambda { diff --git a/src/__mocks__/fs.ts b/src/__mocks__/fs.ts index e2132777..bbadbd3b 100644 --- a/src/__mocks__/fs.ts +++ b/src/__mocks__/fs.ts @@ -1,4 +1,4 @@ -const fs: any = jest.createMockFromModule("fs"); +const fs: any = jest.createMockFromModule('fs'); function readFileSync(input: any) { return input; diff --git a/src/__mocks__/logger.ts b/src/__mocks__/logger.ts index 2aebf45a..6064ff22 100644 --- a/src/__mocks__/logger.ts +++ b/src/__mocks__/logger.ts @@ -1,7 +1,7 @@ // eslint-disable-next-line @typescript-eslint/no-var-requires -const consola = require("consola"); +const consola = require('consola'); -const loggerModule: typeof consola = jest.genMockFromModule("../logger"); +const loggerModule: typeof consola = jest.genMockFromModule('../logger'); loggerModule.logger.withScope = function (): any { return this; diff --git a/src/__tests__/config.test.ts b/src/__tests__/config.test.ts index 3dcaa4ee..5adb2f4a 100644 --- a/src/__tests__/config.test.ts +++ b/src/__tests__/config.test.ts @@ -3,48 +3,48 @@ * configuration). */ -import { readFileSync } from "fs"; -import { dirname, join } from "path"; +import { readFileSync } from 'fs'; +import { dirname, join } from 'path'; -import { compile } from "json-schema-to-typescript"; +import { compile } from 'json-schema-to-typescript'; -import { getProjectConfigSchema, validateConfiguration } from "../config"; +import { getProjectConfigSchema, validateConfiguration } from '../config'; -const configSchemaDir = join(dirname(__dirname), "schemas"); -const configGeneratedTypes = join(configSchemaDir, "project_config.ts"); +const configSchemaDir = join(dirname(__dirname), 'schemas'); +const configGeneratedTypes = join(configSchemaDir, 'project_config.ts'); /** * We compile JSON schema to TypeScript interface as part of tests to compare * it with the existing file. This is done to be promptly notified about any * changes to the JSON schema that are not yet reflected in the TS interface. */ -describe("compile-json-schema-to-typescript", () => { - test("does not make any changes to the compiled interface", async () => { +describe('compile-json-schema-to-typescript', () => { + test('does not make any changes to the compiled interface', async () => { // eslint-disable-next-line @typescript-eslint/no-var-requires - const projectConfig = require("../schemas/projectConfig.schema"); + const projectConfig = require('../schemas/projectConfig.schema'); const storedOutput = readFileSync(configGeneratedTypes, { - encoding: "utf8", + encoding: 'utf8', }); const compileOptions = { - style: { singleQuote: true, trailingComma: "es5" } as any, + style: { singleQuote: true, trailingComma: 'es5' } as any, }; - const generatedOutput = await compile(projectConfig, "", compileOptions); + const generatedOutput = await compile(projectConfig, '', compileOptions); expect(generatedOutput).toBeTruthy(); expect(generatedOutput).toBe(storedOutput); }); }); -describe("validateConfiguration", () => { - test("parses minimal configuration", () => { - const data = { github: { owner: "getsentry", repo: "craft" } }; +describe('validateConfiguration', () => { + test('parses minimal configuration', () => { + const data = { github: { owner: 'getsentry', repo: 'craft' } }; const projectConfig = validateConfiguration(data); expect(projectConfig).toEqual(data); }); - test("fails with empty configuration", () => { + test('fails with empty configuration', () => { // this ensures that we do actually run the expect line in the catch block expect.assertions(1); @@ -56,11 +56,11 @@ describe("validateConfiguration", () => { }); }); -describe("getProjectConfigSchema", () => { - test("returns non-empty object", () => { +describe('getProjectConfigSchema', () => { + test('returns non-empty object', () => { const projectConfigSchema = getProjectConfigSchema(); - expect(projectConfigSchema).toHaveProperty("title"); - expect(projectConfigSchema).toHaveProperty("properties"); + expect(projectConfigSchema).toHaveProperty('title'); + expect(projectConfigSchema).toHaveProperty('properties'); }); }); diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts index 3bc8fccf..642eadb6 100644 --- a/src/__tests__/index.test.ts +++ b/src/__tests__/index.test.ts @@ -1,3 +1,3 @@ -test("it works", () => { +test('it works', () => { expect(true).toBeTruthy(); }); diff --git a/src/artifact_providers/base.ts b/src/artifact_providers/base.ts index da0b9bd0..95843e2e 100644 --- a/src/artifact_providers/base.ts +++ b/src/artifact_providers/base.ts @@ -2,10 +2,10 @@ import { calculateChecksum, HashAlgorithm, HashOutputFormat, -} from "../utils/system"; -import { clearObjectProperties } from "../utils/objects"; -import { ConfigurationError } from "../utils/errors"; -import { logger as loggerRaw } from "../logger"; +} from '../utils/system'; +import { clearObjectProperties } from '../utils/objects'; +import { ConfigurationError } from '../utils/errors'; +import { logger as loggerRaw } from '../logger'; const logger = loggerRaw.withScope(`[artifact-provider]`); @@ -130,7 +130,7 @@ export abstract class BaseArtifactProvider { if (downloadDirectory) { this.defaultDownloadDirectory = downloadDirectory; } else { - throw new ConfigurationError("Download directory cannot be empty!"); + throw new ConfigurationError('Download directory cannot be empty!'); } } @@ -165,7 +165,7 @@ export abstract class BaseArtifactProvider { } else if (this.defaultDownloadDirectory) { finalDownloadDirectory = this.defaultDownloadDirectory; } else { - throw new Error("Download directory not configured!"); + throw new Error('Download directory not configured!'); } const cacheKey = `${finalDownloadDirectory}/${artifact.filename}/${artifact.storedFile.lastUpdated}`; diff --git a/src/artifact_providers/gcs.ts b/src/artifact_providers/gcs.ts index f6102077..07748b39 100644 --- a/src/artifact_providers/gcs.ts +++ b/src/artifact_providers/gcs.ts @@ -2,10 +2,10 @@ import { BaseArtifactProvider, RemoteArtifact, ArtifactProviderConfig, -} from "../artifact_providers/base"; -import { CraftGCSClient, getGCSCredsFromEnv } from "../utils/gcsApi"; -import { ConfigurationError } from "../utils/errors"; -import { logger as loggerRaw } from "../logger"; +} from '../artifact_providers/base'; +import { CraftGCSClient, getGCSCredsFromEnv } from '../utils/gcsApi'; +import { ConfigurationError } from '../utils/errors'; +import { logger as loggerRaw } from '../logger'; const logger = loggerRaw.withScope(`[artifact-provider/gcs]`); @@ -28,10 +28,10 @@ export class GCSArtifactProvider extends BaseArtifactProvider { super(config); const { project_id, client_email, private_key } = getGCSCredsFromEnv( { - name: "CRAFT_GCS_STORE_CREDS_JSON", + name: 'CRAFT_GCS_STORE_CREDS_JSON', }, { - name: "CRAFT_GCS_STORE_CREDS_PATH", + name: 'CRAFT_GCS_STORE_CREDS_PATH', }, logger ); @@ -39,7 +39,7 @@ export class GCSArtifactProvider extends BaseArtifactProvider { // TODO (kmclb) get rid of this check once config validation is working if (!config.bucket) { throw new ConfigurationError( - "No GCS bucket provided in artifact provider config!" + 'No GCS bucket provided in artifact provider config!' ); } diff --git a/src/artifact_providers/github.ts b/src/artifact_providers/github.ts index e8c971f7..1ebd92e2 100644 --- a/src/artifact_providers/github.ts +++ b/src/artifact_providers/github.ts @@ -1,24 +1,24 @@ -import Github from "@octokit/rest"; -import * as fs from "fs"; -import request from "request"; -import * as path from "path"; +import Github from '@octokit/rest'; +import * as fs from 'fs'; +import request from 'request'; +import * as path from 'path'; import { ArtifactProviderConfig, BaseArtifactProvider, RemoteArtifact, -} from "../artifact_providers/base"; -import { getGlobalGithubConfig } from "../config"; -import { logger as loggerRaw } from "../logger"; -import { GithubGlobalConfig } from "../schemas/project_config"; -import { getGithubClient } from "../utils/githubApi"; +} from '../artifact_providers/base'; +import { getGlobalGithubConfig } from '../config'; +import { logger as loggerRaw } from '../logger'; +import { GithubGlobalConfig } from '../schemas/project_config'; +import { getGithubClient } from '../utils/githubApi'; import { detectContentType, scan, withTempFile, withTempDir, -} from "../utils/files"; -import { extractZipArchive } from "../utils/system"; +} from '../utils/files'; +import { extractZipArchive } from '../utils/system'; const MAX_TRIES = 3; @@ -91,7 +91,7 @@ export class GithubArtifactProvider extends BaseArtifactProvider { // https://docs.github.com/en/free-pro-team@latest/rest/reference/actions#artifacts const artifactResponse = (( - await this.github.request("GET /repos/{owner}/{repo}/actions/artifacts", { + await this.github.request('GET /repos/{owner}/{repo}/actions/artifacts', { owner: owner, repo: repo, per_page, @@ -174,11 +174,11 @@ export class GithubArtifactProvider extends BaseArtifactProvider { // we need any here since our github api client doesn't have support for artifacts requests yet request({ uri: archiveResponse.url }) .pipe(file) - .on("finish", () => { + .on('finish', () => { logger.info(`Finished downloading.`); resolve(); }) - .on("error", (error) => { + .on('error', (error) => { reject(error); }); }); @@ -213,12 +213,12 @@ export class GithubArtifactProvider extends BaseArtifactProvider { const { repoName, repoOwner } = this.config; const archiveResponse = (await this.github.request( - "/repos/{owner}/{repo}/actions/artifacts/{artifact_id}/{archive_format}", + '/repos/{owner}/{repo}/actions/artifacts/{artifact_id}/{archive_format}', { owner: repoOwner, repo: repoName, artifact_id: foundArtifact.id, - archive_format: "zip", + archive_format: 'zip', } )) as ArchiveResponse; diff --git a/src/artifact_providers/none.ts b/src/artifact_providers/none.ts index 72da8467..b997948e 100644 --- a/src/artifact_providers/none.ts +++ b/src/artifact_providers/none.ts @@ -2,14 +2,14 @@ import { BaseArtifactProvider, RemoteArtifact, ArtifactProviderConfig, -} from "../artifact_providers/base"; +} from '../artifact_providers/base'; /** * Empty artifact provider that does nothing. */ export class NoneArtifactProvider extends BaseArtifactProvider { public constructor( - config: ArtifactProviderConfig = { repoName: "none", repoOwner: "none" } + config: ArtifactProviderConfig = { repoName: 'none', repoOwner: 'none' } ) { super(config); } @@ -23,7 +23,7 @@ export class NoneArtifactProvider extends BaseArtifactProvider { _downloadDirectory: string ): Promise { return Promise.reject( - new Error("NoneProvider does not suuport file downloads!") + new Error('NoneProvider does not suuport file downloads!') ); } diff --git a/src/artifact_providers/zeus.ts b/src/artifact_providers/zeus.ts index d949fa61..fef07cdd 100644 --- a/src/artifact_providers/zeus.ts +++ b/src/artifact_providers/zeus.ts @@ -2,16 +2,16 @@ import { Artifact as ZeusArtifact, Client as ZeusClient, Status, -} from "@zeus-ci/sdk"; -import * as _ from "lodash"; +} from '@zeus-ci/sdk'; +import * as _ from 'lodash'; import { BaseArtifactProvider, RemoteArtifact, ArtifactProviderConfig, -} from "../artifact_providers/base"; -import { checkEnvForPrerequisite } from "../utils/env"; -import { logger as loggerRaw } from "../logger"; +} from '../artifact_providers/base'; +import { checkEnvForPrerequisite } from '../utils/env'; +import { logger as loggerRaw } from '../logger'; const logger = loggerRaw.withScope(`[artifact-provider/zeus]`); @@ -30,8 +30,8 @@ export class ZeusArtifactProvider extends BaseArtifactProvider { public constructor(config: ArtifactProviderConfig) { super(config); checkEnvForPrerequisite({ - legacyName: "ZEUS_TOKEN", - name: "ZEUS_API_TOKEN", + legacyName: 'ZEUS_TOKEN', + name: 'ZEUS_API_TOKEN', }); // We currently need ZEUS_TOKEN set for zeus-sdk to work properly if (!process.env.ZEUS_TOKEN) { @@ -96,10 +96,10 @@ export class ZeusArtifactProvider extends BaseArtifactProvider { name: storedFilename, size, }, - id: "", + id: '', name, status: Status.UNKNOWN, - type: type || "", + type: type || '', updated_at, }; } @@ -143,7 +143,7 @@ export class ZeusArtifactProvider extends BaseArtifactProvider { // return an empty list, whereas in the latter case (unknown commit), it // will error. This error message check and the length check below are // here to disambiguate those two situations. - const errorMessage: string = e.message || ""; + const errorMessage: string = e.message || ''; if (errorMessage.match(/404 not found|resource not found/i)) { logger.debug(`Revision \`${revision}\` not found!`); } @@ -171,7 +171,7 @@ export class ZeusArtifactProvider extends BaseArtifactProvider { const sortedZeusArtifacts = _.sortBy( zeusArtifactObjects, (zeusArtifactObject) => - Date.parse(zeusArtifactObject.updated_at || "") || 0 + Date.parse(zeusArtifactObject.updated_at || '') || 0 ); return sortedZeusArtifacts[sortedZeusArtifacts.length - 1]; } diff --git a/src/commands/__tests__/prepare.test.ts b/src/commands/__tests__/prepare.test.ts index 47c3847a..58a248e5 100644 --- a/src/commands/__tests__/prepare.test.ts +++ b/src/commands/__tests__/prepare.test.ts @@ -1,36 +1,36 @@ -import { join as pathJoin } from "path"; -import { spawnProcess } from "../../utils/system"; -import { runPreReleaseCommand } from "../prepare"; +import { join as pathJoin } from 'path'; +import { spawnProcess } from '../../utils/system'; +import { runPreReleaseCommand } from '../prepare'; -jest.mock("../../utils/system"); +jest.mock('../../utils/system'); -describe("runPreReleaseCommand", () => { - const newVersion = "2.3.4"; +describe('runPreReleaseCommand', () => { + const newVersion = '2.3.4'; const mockedSpawnProcess = spawnProcess as jest.Mock; beforeEach(() => { jest.clearAllMocks(); }); - test("runs with default command", async () => { + test('runs with default command', async () => { expect.assertions(1); await runPreReleaseCommand(newVersion); expect(mockedSpawnProcess).toBeCalledWith( - "/bin/bash", - [pathJoin("scripts", "bump-version.sh"), "", newVersion], + '/bin/bash', + [pathJoin('scripts', 'bump-version.sh'), '', newVersion], { env: { ...process.env, CRAFT_NEW_VERSION: newVersion, - CRAFT_OLD_VERSION: "", + CRAFT_OLD_VERSION: '', }, } ); }); - test("runs with custom command", async () => { + test('runs with custom command', async () => { expect.assertions(1); await runPreReleaseCommand( @@ -39,13 +39,13 @@ describe("runPreReleaseCommand", () => { ); expect(mockedSpawnProcess).toBeCalledWith( - "python", - ["./increase_version.py", "argument 1", "", newVersion], + 'python', + ['./increase_version.py', 'argument 1', '', newVersion], { env: { ...process.env, CRAFT_NEW_VERSION: newVersion, - CRAFT_OLD_VERSION: "", + CRAFT_OLD_VERSION: '', }, } ); diff --git a/src/commands/__tests__/publish.test.ts b/src/commands/__tests__/publish.test.ts index ba6408fc..6ab58267 100644 --- a/src/commands/__tests__/publish.test.ts +++ b/src/commands/__tests__/publish.test.ts @@ -1,11 +1,11 @@ -import { join as pathJoin } from "path"; -import { spawnProcess, hasExecutable } from "../../utils/system"; -import { runPostReleaseCommand } from "../publish"; +import { join as pathJoin } from 'path'; +import { spawnProcess, hasExecutable } from '../../utils/system'; +import { runPostReleaseCommand } from '../publish'; -jest.mock("../../utils/system"); +jest.mock('../../utils/system'); -describe("runPostReleaseCommand", () => { - const newVersion = "2.3.4"; +describe('runPostReleaseCommand', () => { + const newVersion = '2.3.4'; const mockedSpawnProcess = spawnProcess as jest.Mock; const mockedHasExecutable = hasExecutable as jest.Mock; @@ -13,27 +13,27 @@ describe("runPostReleaseCommand", () => { jest.clearAllMocks(); }); - describe("default script", () => { - test("runs when script exists", async () => { + describe('default script', () => { + test('runs when script exists', async () => { mockedHasExecutable.mockReturnValue(true); expect.assertions(1); await runPostReleaseCommand(newVersion); expect(mockedSpawnProcess).toBeCalledWith( - "/bin/bash", - [pathJoin("scripts", "post-release.sh"), "", newVersion], + '/bin/bash', + [pathJoin('scripts', 'post-release.sh'), '', newVersion], { env: { ...process.env, CRAFT_NEW_VERSION: newVersion, - CRAFT_OLD_VERSION: "", + CRAFT_OLD_VERSION: '', }, } ); }); - test("skips when script does not exist", async () => { + test('skips when script does not exist', async () => { mockedHasExecutable.mockReturnValue(false); expect.assertions(1); @@ -43,7 +43,7 @@ describe("runPostReleaseCommand", () => { }); }); - test("runs with custom command", async () => { + test('runs with custom command', async () => { expect.assertions(1); await runPostReleaseCommand( @@ -52,13 +52,13 @@ describe("runPostReleaseCommand", () => { ); expect(mockedSpawnProcess).toBeCalledWith( - "python", - ["./increase_version.py", "argument 1", "", newVersion], + 'python', + ['./increase_version.py', 'argument 1', '', newVersion], { env: { ...process.env, CRAFT_NEW_VERSION: newVersion, - CRAFT_OLD_VERSION: "", + CRAFT_OLD_VERSION: '', }, } ); diff --git a/src/commands/artifacts.ts b/src/commands/artifacts.ts index 09d0a678..ea4a9c0f 100644 --- a/src/commands/artifacts.ts +++ b/src/commands/artifacts.ts @@ -1,11 +1,11 @@ -import { Argv, CommandBuilder } from "yargs"; +import { Argv, CommandBuilder } from 'yargs'; -import * as download from "./artifacts_cmds/download"; -import * as list from "./artifacts_cmds/list"; +import * as download from './artifacts_cmds/download'; +import * as list from './artifacts_cmds/list'; -export const command = ["artifacts "]; -export const aliases = ["a", "artifact"]; -export const description = "📦 Manage artifacts"; +export const command = ['artifacts ']; +export const aliases = ['a', 'artifact']; +export const description = '📦 Manage artifacts'; /** * Common options for `artifacts` commands @@ -16,13 +16,13 @@ export interface ArtifactsOptions { export const builder: CommandBuilder = (yargs: Argv) => yargs - .option("rev", { - alias: "r", - description: "Revision", - type: "string", + .option('rev', { + alias: 'r', + description: 'Revision', + type: 'string', }) .demandCommand() - .demandOption("rev", "Please specify the revision") + .demandOption('rev', 'Please specify the revision') .command(list) .command(download); diff --git a/src/commands/artifacts_cmds/download.ts b/src/commands/artifacts_cmds/download.ts index d45418a2..054112f1 100644 --- a/src/commands/artifacts_cmds/download.ts +++ b/src/commands/artifacts_cmds/download.ts @@ -1,35 +1,35 @@ -import * as _ from "lodash"; -import { logger } from "../../logger"; -import { ArtifactsOptions } from "../artifacts"; -import { getArtifactProviderFromConfig } from "../../config"; -import { handleGlobalError, ConfigurationError } from "../../utils/errors"; -import { Argv, CommandBuilder } from "yargs"; -import { resolve } from "path"; -import { existsSync, lstatSync } from "fs"; -import mkdirp = require("mkdirp"); -import { NoneArtifactProvider } from "../../artifact_providers/none"; +import * as _ from 'lodash'; +import { logger } from '../../logger'; +import { ArtifactsOptions } from '../artifacts'; +import { getArtifactProviderFromConfig } from '../../config'; +import { handleGlobalError, ConfigurationError } from '../../utils/errors'; +import { Argv, CommandBuilder } from 'yargs'; +import { resolve } from 'path'; +import { existsSync, lstatSync } from 'fs'; +import mkdirp = require('mkdirp'); +import { NoneArtifactProvider } from '../../artifact_providers/none'; -export const command = ["download [NAME..]"]; -export const aliases = ["d", "get"]; -export const description = "Download artifacts"; +export const command = ['download [NAME..]']; +export const aliases = ['d', 'get']; +export const description = 'Download artifacts'; export const builder: CommandBuilder = (yargs: Argv) => yargs - .positional("NAME", { - alias: "names", - description: "Artifact name to download", - type: "string", + .positional('NAME', { + alias: 'names', + description: 'Artifact name to download', + type: 'string', }) - .array("NAME") - .option("all", { - alias: "a", + .array('NAME') + .option('all', { + alias: 'a', default: false, - description: "Download all artifacts", - type: "boolean", + description: 'Download all artifacts', + type: 'boolean', }) - .option("directory", { - alias: "d", - description: "Target directory", - type: "string", + .option('directory', { + alias: 'd', + description: 'Target directory', + type: 'string', }); /** Options for "download" command */ @@ -70,7 +70,7 @@ async function prepareOutputDirectory( */ async function handlerMain(argv: ArtifactsDownloadOptions): Promise { if (!argv.all && argv.names.length === 0) { - throw new ConfigurationError("No names to download, exiting."); + throw new ConfigurationError('No names to download, exiting.'); } const revision = argv.rev; diff --git a/src/commands/artifacts_cmds/list.ts b/src/commands/artifacts_cmds/list.ts index e0300373..1dcc7e6b 100644 --- a/src/commands/artifacts_cmds/list.ts +++ b/src/commands/artifacts_cmds/list.ts @@ -1,13 +1,13 @@ -import { logger, formatTable } from "../../logger"; -import { ArtifactsOptions } from "../artifacts"; -import { getArtifactProviderFromConfig } from "../../config"; -import { handleGlobalError } from "../../utils/errors"; -import { formatSize } from "../../utils/strings"; -import { NoneArtifactProvider } from "../../artifact_providers/none"; +import { logger, formatTable } from '../../logger'; +import { ArtifactsOptions } from '../artifacts'; +import { getArtifactProviderFromConfig } from '../../config'; +import { handleGlobalError } from '../../utils/errors'; +import { formatSize } from '../../utils/strings'; +import { NoneArtifactProvider } from '../../artifact_providers/none'; -export const command = ["list"]; -export const aliases = ["l"]; -export const description = "List artifacts"; +export const command = ['list']; +export const aliases = ['l']; +export const description = 'List artifacts'; /** * Body of 'artifacts list' command @@ -33,13 +33,13 @@ async function handlerMain(argv: ArtifactsOptions): Promise { const artifactData = artifacts.map((ar) => [ ar.filename, formatSize(ar.storedFile.size), - ar.storedFile.lastUpdated || "", + ar.storedFile.lastUpdated || '', ]); const table = formatTable( { - head: ["File Name", "Size", "Updated"], - style: { head: ["cyan"] }, + head: ['File Name', 'Size', 'Updated'], + style: { head: ['cyan'] }, }, artifactData ); diff --git a/src/commands/prepare.ts b/src/commands/prepare.ts index 9acf8600..ca8c5c3d 100644 --- a/src/commands/prepare.ts +++ b/src/commands/prepare.ts @@ -1,69 +1,69 @@ -import { existsSync, promises as fsPromises } from "fs"; -import { dirname, join, relative } from "path"; -import * as shellQuote from "shell-quote"; -import simpleGit, { SimpleGit } from "simple-git"; -import { Arguments, Argv, CommandBuilder } from "yargs"; +import { existsSync, promises as fsPromises } from 'fs'; +import { dirname, join, relative } from 'path'; +import * as shellQuote from 'shell-quote'; +import simpleGit, { SimpleGit } from 'simple-git'; +import { Arguments, Argv, CommandBuilder } from 'yargs'; import { checkMinimalConfigVersion, getConfigFilePath, getConfiguration, DEFAULT_RELEASE_BRANCH_NAME, -} from "../config"; -import { logger } from "../logger"; -import { ChangelogPolicy } from "../schemas/project_config"; +} from '../config'; +import { logger } from '../logger'; +import { ChangelogPolicy } from '../schemas/project_config'; import { DEFAULT_CHANGELOG_PATH, DEFAULT_UNRELEASED_TITLE, findChangeset, removeChangeset, prependChangeset, -} from "../utils/changes"; +} from '../utils/changes'; import { ConfigurationError, handleGlobalError, reportError, -} from "../utils/errors"; -import { getDefaultBranch, getGithubClient } from "../utils/githubApi"; -import { isDryRun } from "../utils/helpers"; -import { formatJson } from "../utils/strings"; -import { sleepAsync, spawnProcess } from "../utils/system"; -import { isValidVersion, versionToTag } from "../utils/version"; +} from '../utils/errors'; +import { getDefaultBranch, getGithubClient } from '../utils/githubApi'; +import { isDryRun } from '../utils/helpers'; +import { formatJson } from '../utils/strings'; +import { sleepAsync, spawnProcess } from '../utils/system'; +import { isValidVersion, versionToTag } from '../utils/version'; -import { handler as publishMainHandler, PublishOptions } from "./publish"; +import { handler as publishMainHandler, PublishOptions } from './publish'; -export const command = ["prepare NEW-VERSION"]; -export const aliases = ["p", "prerelease", "prepublish", "prepare", "release"]; -export const description = "🚢 Prepare a new release branch"; +export const command = ['prepare NEW-VERSION']; +export const aliases = ['p', 'prerelease', 'prepublish', 'prepare', 'release']; +export const description = '🚢 Prepare a new release branch'; /** Default path to bump-version script, relative to project root */ -const DEFAULT_BUMP_VERSION_PATH = join("scripts", "bump-version.sh"); +const DEFAULT_BUMP_VERSION_PATH = join('scripts', 'bump-version.sh'); export const builder: CommandBuilder = (yargs: Argv) => yargs - .positional("NEW-VERSION", { - description: "The new version you want to release", - type: "string", + .positional('NEW-VERSION', { + description: 'The new version you want to release', + type: 'string', }) - .option("no-push", { + .option('no-push', { default: false, - description: "Do not push the release branch", - type: "boolean", + description: 'Do not push the release branch', + type: 'boolean', }) - .option("no-git-checks", { + .option('no-git-checks', { default: false, - description: "Ignore local git changes and unsynchronized remotes", - type: "boolean", + description: 'Ignore local git changes and unsynchronized remotes', + type: 'boolean', }) - .option("no-changelog", { + .option('no-changelog', { default: false, - description: "Do not check for changelog entries", - type: "boolean", + description: 'Do not check for changelog entries', + type: 'boolean', }) - .option("publish", { + .option('publish', { default: false, description: 'Run "publish" right after "release"', - type: "boolean", + type: 'boolean', }) .check(checkVersionOrPart); @@ -98,8 +98,8 @@ const SLEEP_BEFORE_PUBLISH_SECONDS = 30; */ function checkVersionOrPart(argv: Arguments, _opt: any): any { const version = argv.newVersion; - if (["major", "minor", "patch"].indexOf(version) > -1) { - throw Error("Version part is not supported yet"); + if (['major', 'minor', 'patch'].indexOf(version) > -1) { + throw Error('Version part is not supported yet'); } else if (isValidVersion(version)) { return true; } else { @@ -124,7 +124,7 @@ async function createReleaseBranch( const branchPrefix = releaseBranchPrefix || DEFAULT_RELEASE_BRANCH_NAME; const branchName = `${branchPrefix}/${newVersion}`; - const branchHead = await git.raw(["show-ref", "--heads", branchName]); + const branchHead = await git.raw(['show-ref', '--heads', branchName]); // in case `show-ref` can't find a branch it returns `null` if (branchHead) { @@ -141,7 +141,7 @@ async function createReleaseBranch( logger.info(`Created a new release branch: "${branchName}"`); logger.info(`Switched to branch "${branchName}"`); } else { - logger.info("[dry-run] Not creating a new release branch"); + logger.info('[dry-run] Not creating a new release branch'); } return branchName; } @@ -163,14 +163,14 @@ async function pushReleaseBranch( logger.info(`Pushing the release branch "${branchName}"...`); // TODO check remote somehow if (!isDryRun()) { - await git.push(remoteName, branchName, ["--set-upstream"]); + await git.push(remoteName, branchName, ['--set-upstream']); } else { - logger.info("[dry-run] Not pushing the release branch."); + logger.info('[dry-run] Not pushing the release branch.'); } } else { - logger.info("Not pushing the release branch."); + logger.info('Not pushing the release branch.'); logger.info( - "You can push this branch later using the following command:", + 'You can push this branch later using the following command:', ` $ git push -u ${remoteName} "${branchName}"` ); } @@ -189,15 +189,15 @@ async function commitNewVersion( const message = `release: ${newVersion}`; const repoStatus = await git.status(); if (!(repoStatus.created.length || repoStatus.modified.length)) { - reportError("Nothing to commit: has the pre-release command done its job?"); + reportError('Nothing to commit: has the pre-release command done its job?'); } - logger.info("Committing the release changes..."); + logger.info('Committing the release changes...'); logger.debug(`Commit message: "${message}"`); if (!isDryRun()) { - await git.commit(message, ["--all"]); + await git.commit(message, ['--all']); } else { - logger.info("[dry-run] Not committing the changes."); + logger.info('[dry-run] Not committing the changes.'); } } @@ -218,19 +218,19 @@ export async function runPreReleaseCommand( let args: string[]; if (preReleaseCommand !== undefined && preReleaseCommand.length === 0) { // Not running pre-release command - logger.warn("Not running the pre-release command: no command specified"); + logger.warn('Not running the pre-release command: no command specified'); return false; } else if (preReleaseCommand) { [sysCommand, ...args] = shellQuote.parse(preReleaseCommand) as string[]; } else { - sysCommand = "/bin/bash"; + sysCommand = '/bin/bash'; args = [DEFAULT_BUMP_VERSION_PATH]; } - args = [...args, "", newVersion]; + args = [...args, '', newVersion]; logger.info(`Running the pre-release command...`); const additionalEnv = { CRAFT_NEW_VERSION: newVersion, - CRAFT_OLD_VERSION: "", + CRAFT_OLD_VERSION: '', }; await spawnProcess(sysCommand, args, { env: { ...process.env, ...additionalEnv }, @@ -251,17 +251,17 @@ async function checkGitState( checkGitStatus = true ): Promise { if (!checkGitStatus) { - logger.warn("Not checking the status of the local repository"); + logger.warn('Not checking the status of the local repository'); return; } - logger.info("Checking the local repository status..."); + logger.info('Checking the local repository status...'); const isRepo = await git.checkIsRepo(); if (!isRepo) { - throw new ConfigurationError("Not a git repository!"); + throw new ConfigurationError('Not a git repository!'); } const repoStatus = await git.status(); - logger.debug("Repository status:", formatJson(repoStatus)); + logger.debug('Repository status:', formatJson(repoStatus)); // Check that we are on master // TODO check what's here when we are in a detached state @@ -280,8 +280,8 @@ async function checkGitState( repoStatus.staged.length ) { reportError( - "Your repository is in a dirty state. " + - "Please stash or commit the pending changes.", + 'Your repository is in a dirty state. ' + + 'Please stash or commit the pending changes.', logger ); } @@ -317,7 +317,7 @@ async function execPublish(newVersion: string): Promise { if (!isDryRun()) { await sleepAsync(SLEEP_BEFORE_PUBLISH_SECONDS * 1000); } else { - logger.info("[dry-run] Not wasting time on sleep"); + logger.info('[dry-run] Not wasting time on sleep'); } try { @@ -331,7 +331,7 @@ async function execPublish(newVersion: string): Promise { ); throw e; } - throw new Error("Unreachable"); + throw new Error('Unreachable'); } /** @@ -347,7 +347,7 @@ async function checkForExistingTag( checkGitStatus = true ): Promise { if (!checkGitStatus) { - logger.warn("Not checking if the version (git tag) already exists"); + logger.warn('Not checking if the version (git tag) already exists'); } const gitTag = versionToTag(newVersion); @@ -384,11 +384,11 @@ async function prepareChangelog( ); } - logger.info("Checking the changelog..."); + logger.info('Checking the changelog...'); logger.debug(`Changelog policy: "${changelogPolicy}".`); - const relativePath = relative("", changelogPath); - if (relativePath.startsWith(".")) { + const relativePath = relative('', changelogPath); + if (relativePath.startsWith('.')) { throw new ConfigurationError(`Invalid changelog path: "${changelogPath}"`); } @@ -411,7 +411,7 @@ async function prepareChangelog( // eslint-disable-next-line no-case-declarations let replaceSection; if (!changeset) { - changeset = { name: newVersion, body: "" }; + changeset = { name: newVersion, body: '' }; } if (!changeset.body) { replaceSection = changeset.name; @@ -432,7 +432,7 @@ async function prepareChangelog( if (!isDryRun()) { await fsPromises.writeFile(relativePath, changelogString); } else { - logger.info("[dry-run] Not updating changelog file."); + logger.info('[dry-run] Not updating changelog file.'); logger.debug(`New changelog:\n${changelogString}`); } @@ -466,7 +466,7 @@ async function switchToDefaultBranch( if (!isDryRun()) { await git.checkout(defaultBranch); } else { - logger.info("[dry-run] Not switching branches."); + logger.info('[dry-run] Not switching branches.'); } } @@ -476,7 +476,7 @@ async function switchToDefaultBranch( * @param argv Command-line arguments */ export async function releaseMain(argv: ReleaseOptions): Promise { - logger.debug("Argv: ", JSON.stringify(argv)); + logger.debug('Argv: ', JSON.stringify(argv)); checkMinimalConfigVersion(); // Get repo configuration @@ -534,7 +534,7 @@ export async function releaseMain(argv: ReleaseOptions): Promise { // Commit the pending changes await commitNewVersion(git, newVersion); } else { - logger.debug("Not committing anything since preReleaseCommand is empty."); + logger.debug('Not committing anything since preReleaseCommand is empty.'); } // Push the release branch @@ -563,7 +563,7 @@ export async function releaseMain(argv: ReleaseOptions): Promise { * @returns Git remote name from environment or default */ function getRemoteName(): string { - return process.env.CRAFT_REMOTE || "origin"; + return process.env.CRAFT_REMOTE || 'origin'; } export const handler = async (args: { diff --git a/src/commands/publish.ts b/src/commands/publish.ts index 1e79b134..27b5ab91 100644 --- a/src/commands/publish.ts +++ b/src/commands/publish.ts @@ -1,16 +1,16 @@ -import * as Github from "@octokit/rest"; -import * as inquirer from "inquirer"; -import { Arguments, Argv, CommandBuilder } from "yargs"; -import chalk from "chalk"; +import * as Github from '@octokit/rest'; +import * as inquirer from 'inquirer'; +import { Arguments, Argv, CommandBuilder } from 'yargs'; +import chalk from 'chalk'; import { existsSync, readFileSync, writeFileSync, promises as fsPromises, -} from "fs"; -import { join } from "path"; -import shellQuote from "shell-quote"; -import stringLength from "string-length"; +} from 'fs'; +import { join } from 'path'; +import shellQuote from 'shell-quote'; +import stringLength from 'string-length'; import { checkMinimalConfigVersion, @@ -18,38 +18,38 @@ import { getStatusProviderFromConfig, getArtifactProviderFromConfig, DEFAULT_RELEASE_BRANCH_NAME, -} from "../config"; -import { formatTable, logger } from "../logger"; -import { GithubGlobalConfig, TargetConfig } from "../schemas/project_config"; +} from '../config'; +import { formatTable, logger } from '../logger'; +import { GithubGlobalConfig, TargetConfig } from '../schemas/project_config'; import { getAllTargetNames, getTargetByName, getTargetId, SpecialTarget, -} from "../targets"; -import { BaseTarget } from "../targets/base"; -import { coerceType, handleGlobalError, reportError } from "../utils/errors"; -import { withTempDir } from "../utils/files"; -import { stringToRegexp } from "../utils/filters"; -import { getGithubClient, mergeReleaseBranch } from "../utils/githubApi"; -import { isDryRun } from "../utils/helpers"; -import { hasInput } from "../utils/noInput"; -import { formatSize, formatJson } from "../utils/strings"; +} from '../targets'; +import { BaseTarget } from '../targets/base'; +import { coerceType, handleGlobalError, reportError } from '../utils/errors'; +import { withTempDir } from '../utils/files'; +import { stringToRegexp } from '../utils/filters'; +import { getGithubClient, mergeReleaseBranch } from '../utils/githubApi'; +import { isDryRun } from '../utils/helpers'; +import { hasInput } from '../utils/noInput'; +import { formatSize, formatJson } from '../utils/strings'; import { catchKeyboardInterrupt, hasExecutable, spawnProcess, -} from "../utils/system"; -import { isValidVersion } from "../utils/version"; -import { BaseStatusProvider } from "../status_providers/base"; -import { BaseArtifactProvider } from "../artifact_providers/base"; +} from '../utils/system'; +import { isValidVersion } from '../utils/version'; +import { BaseStatusProvider } from '../status_providers/base'; +import { BaseArtifactProvider } from '../artifact_providers/base'; /** Default path to post-release script, relative to project root */ -const DEFAULT_POST_RELEASE_SCRIPT_PATH = join("scripts", "post-release.sh"); +const DEFAULT_POST_RELEASE_SCRIPT_PATH = join('scripts', 'post-release.sh'); -export const command = ["publish NEW-VERSION"]; -export const aliases = ["pp", "publish"]; -export const description = "🛫 Publish artifacts"; +export const command = ['publish NEW-VERSION']; +export const aliases = ['pp', 'publish']; +export const description = '🛫 Publish artifacts'; export const builder: CommandBuilder = (yargs: Argv) => { const definedTargets = getConfiguration().targets || []; @@ -59,48 +59,48 @@ export const builder: CommandBuilder = (yargs: Argv) => { .map(getTargetId); return yargs - .positional("NEW-VERSION", { - description: "Version to publish", - type: "string", + .positional('NEW-VERSION', { + description: 'Version to publish', + type: 'string', }) - .option("target", { - alias: "t", + .option('target', { + alias: 't', choices: allowedTargetNames.concat([ SpecialTarget.All, SpecialTarget.None, ]), default: SpecialTarget.All, - description: "Publish to this target", - type: "string", + description: 'Publish to this target', + type: 'string', }) - .option("rev", { - alias: "r", + .option('rev', { + alias: 'r', description: - "Source revision (git SHA or tag) to publish (if not release branch head)", - type: "string", + 'Source revision (git SHA or tag) to publish (if not release branch head)', + type: 'string', }) - .option("no-merge", { + .option('no-merge', { default: false, - description: "Do not merge the release branch after publishing", - type: "boolean", + description: 'Do not merge the release branch after publishing', + type: 'boolean', }) - .option("keep-branch", { + .option('keep-branch', { default: false, - description: "Do not remove release branch after merging it", - type: "boolean", + description: 'Do not remove release branch after merging it', + type: 'boolean', }) - .option("keep-downloads", { + .option('keep-downloads', { default: false, - description: "Keep all downloaded files", - type: "boolean", + description: 'Keep all downloaded files', + type: 'boolean', }) - .option("no-status-check", { + .option('no-status-check', { default: false, - description: "Do not check for build status", - type: "boolean", + description: 'Do not check for build status', + type: 'boolean', }) .check(checkVersion) - .demandOption("new-version", "Please specify the version to publish"); + .demandOption('new-version', 'Please specify the version to publish'); }; /** Command line options. */ @@ -157,8 +157,8 @@ async function publishToTarget( const publishMessage = `=== Publishing to target: ${chalk.bold( chalk.cyan(getTargetId(target.config)) )} ===`; - const delim = Array(stringLength(publishMessage) + 1).join("="); - logger.info(" "); + const delim = Array(stringLength(publishMessage) + 1).join('='); + logger.info(' '); logger.info(delim); logger.info(publishMessage); logger.info(delim); @@ -180,26 +180,26 @@ async function printRevisionSummary( const artifactData = artifacts.map((ar) => [ ar.filename, formatSize(ar.storedFile.size), - ar.storedFile.lastUpdated || "", + ar.storedFile.lastUpdated || '', // sometimes mimeTypes are stored with the encoding included, e.g. // `application/javascript; charset=utf-8`, but we only really care about // the first part - (ar.mimeType && ar.mimeType.split(";")[0]) || "", + (ar.mimeType && ar.mimeType.split(';')[0]) || '', ]); // sort alphabetically by filename artifactData.sort((a1, a2) => (a1[0] < a2[0] ? -1 : a1[0] > a2[0] ? 1 : 0)); const table = formatTable( { - head: ["File Name", "Size", "Updated", "ContentType"], - style: { head: ["cyan"] }, + head: ['File Name', 'Size', 'Updated', 'ContentType'], + style: { head: ['cyan'] }, }, artifactData ); - logger.info(" "); + logger.info(' '); logger.info(`Available artifacts: \n${table.toString()}\n`); } else { - logger.warn("No artifacts found for the revision."); + logger.warn('No artifacts found for the revision.'); } } @@ -207,19 +207,19 @@ async function printRevisionSummary( * Prompt the user that everything is OK and we should proceed with publishing */ async function promptConfirmation(targetList: BaseTarget[]): Promise { - logger.info("Publishing to targets:"); + logger.info('Publishing to targets:'); logger.info( - targetList.map((target) => ` - ${getTargetId(target.config)}`).join("\n") + targetList.map((target) => ` - ${getTargetId(target.config)}`).join('\n') ); - logger.info(" "); + logger.info(' '); if (hasInput()) { const questions = [ { message: 'Is everything OK? Type "yes" to proceed:', - name: "readyToPublish", - type: "input", + name: 'readyToPublish', + type: 'input', // Force the user to type something that is not empty or one letter such // as y/n to make sure this is a concious choice. validate: (input: string) => @@ -227,13 +227,13 @@ async function promptConfirmation(targetList: BaseTarget[]): Promise { }, ]; const answers = (await inquirer.prompt(questions)) as any; - const readyToPublish = coerceType(answers.readyToPublish, "string"); - if (readyToPublish.toLowerCase() !== "yes") { - logger.error("Oh, okay. Aborting."); + const readyToPublish = coerceType(answers.readyToPublish, 'string'); + if (readyToPublish.toLowerCase() !== 'yes') { + logger.error('Oh, okay. Aborting.'); process.exit(1); } } else { - logger.debug("Skipping the prompting."); + logger.debug('Skipping the prompting.'); } } @@ -241,7 +241,7 @@ async function getTargetList( targetConfigList: TargetConfig[], artifactProvider: BaseArtifactProvider ): Promise { - logger.debug("Initializing targets"); + logger.debug('Initializing targets'); const targetList: BaseTarget[] = []; for (const targetConfig of targetConfigList) { const targetClass = getTargetByName(targetConfig.name); @@ -283,7 +283,7 @@ async function checkRequiredArtifacts( if (!requiredNames || requiredNames.length === 0) { return; } - logger.debug("Checking that the required artifact names are present..."); + logger.debug('Checking that the required artifact names are present...'); const artifacts = await artifactProvider.listArtifactsForRevision(revision); // innocent until proven guilty... @@ -334,13 +334,13 @@ async function checkRevisionStatus( } try { - logger.debug("Fetching repository information..."); + logger.debug('Fetching repository information...'); // This will additionally check that the user has proper permissions const repositoryInfo = await statusProvider.getRepositoryInfo(); logger.debug(`Repository info received: "${formatJson(repositoryInfo)}"`); } catch (e) { reportError( - "Cannot get repository information from Zeus. Check your configuration and credentials. " + + 'Cannot get repository information from Zeus. Check your configuration and credentials. ' + `Error: ${e.message}` ); } @@ -368,7 +368,7 @@ async function handleReleaseBranch( keepBranch = false ): Promise { if (!branchName || skipMerge) { - logger.info("Skipping the merge step."); + logger.info('Skipping the merge step.'); return; } @@ -381,11 +381,11 @@ async function handleReleaseBranch( branchName ); } else { - logger.info("[dry-run] Not merging the release branch"); + logger.info('[dry-run] Not merging the release branch'); } if (keepBranch) { - logger.info("Not deleting the release branch."); + logger.info('Not deleting the release branch.'); } else { const ref = `heads/${branchName}`; logger.debug(`Deleting the release branch, ref: ${ref}`); @@ -401,7 +401,7 @@ async function handleReleaseBranch( ); logger.info(`Removed the remote branch: "${branchName}"`); } else { - logger.info("[dry-run] Not deleting the remote branch"); + logger.info('[dry-run] Not deleting the remote branch'); } } } @@ -423,12 +423,12 @@ export async function runPostReleaseCommand( let args: shellQuote.ParseEntry[]; if (postReleaseCommand !== undefined && postReleaseCommand.length === 0) { // Not running post-release command - logger.debug("Not running the post-release command: no command specified"); + logger.debug('Not running the post-release command: no command specified'); return false; } else if (postReleaseCommand) { [sysCommand, ...args] = shellQuote.parse(postReleaseCommand); } else if (hasExecutable(DEFAULT_POST_RELEASE_SCRIPT_PATH)) { - sysCommand = "/bin/bash"; + sysCommand = '/bin/bash'; args = [DEFAULT_POST_RELEASE_SCRIPT_PATH]; } else { // Not running post-release command @@ -437,11 +437,11 @@ export async function runPostReleaseCommand( ); return false; } - args = [...args, "", newVersion]; + args = [...args, '', newVersion]; logger.info(`Running the post-release command...`); const additionalEnv = { CRAFT_NEW_VERSION: newVersion, - CRAFT_OLD_VERSION: "", + CRAFT_OLD_VERSION: '', }; await spawnProcess(sysCommand as string, args as string[], { env: { ...process.env, ...additionalEnv }, @@ -455,7 +455,7 @@ export async function runPostReleaseCommand( * @param argv Command-line arguments */ export async function publishMain(argv: PublishOptions): Promise { - logger.debug("Argv:", JSON.stringify(argv)); + logger.debug('Argv:', JSON.stringify(argv)); checkMinimalConfigVersion(); // Get publishing configuration @@ -470,7 +470,7 @@ export async function publishMain(argv: PublishOptions): Promise { let revision: string; let branchName; if (argv.rev) { - branchName = ""; + branchName = ''; logger.debug( `Fetching GitHub information for provided revision: "${argv.rev}"` ); @@ -486,7 +486,7 @@ export async function publishMain(argv: PublishOptions): Promise { config.releaseBranchPrefix || DEFAULT_RELEASE_BRANCH_NAME; branchName = `${branchPrefix}/${newVersion}`; - logger.debug("Fetching branch information", branchName); + logger.debug('Fetching branch information', branchName); const response = await githubClient.repos.getBranch({ branch: branchName, owner: githubConfig.owner, @@ -494,7 +494,7 @@ export async function publishMain(argv: PublishOptions): Promise { }); revision = response.data.commit.sha; } - logger.debug("Revision to publish: ", revision); + logger.debug('Revision to publish: ', revision); const statusProvider = getStatusProviderFromConfig(); const artifactProvider = getArtifactProviderFromConfig(); @@ -509,7 +509,7 @@ export async function publishMain(argv: PublishOptions): Promise { // Find targets let targetsToPublish: Set = new Set( - (typeof argv.target === "string" ? [argv.target] : argv.target) || [ + (typeof argv.target === 'string' ? [argv.target] : argv.target) || [ SpecialTarget.All, ] ); @@ -556,7 +556,7 @@ export async function publishMain(argv: PublishOptions): Promise { !earlierStateExists && targetConfigList.length === 0 ) { - logger.warn("No valid targets detected! Exiting."); + logger.warn('No valid targets detected! Exiting.'); return undefined; } @@ -578,17 +578,17 @@ export async function publishMain(argv: PublishOptions): Promise { if (argv.keepDownloads) { logger.info( - "Directory with the downloaded artifacts will not be removed", + 'Directory with the downloaded artifacts will not be removed', `Path: ${downloadDirectory}` ); } }, !argv.keepDownloads); - logger.info(" "); + logger.info(' '); } if (argv.rev) { - logger.info("Not merging any branches because revision was specified."); + logger.info('Not merging any branches because revision was specified.'); } else if ( targetsToPublish.has(SpecialTarget.All) || targetsToPublish.has(SpecialTarget.None) || @@ -614,11 +614,11 @@ export async function publishMain(argv: PublishOptions): Promise { logger.success(`Version ${newVersion} has been published!`); } else { const msg = [ - "The release branch was not merged because you published only to specific targets.", - "After all the targets are published, run the following command to merge the release branch:", + 'The release branch was not merged because you published only to specific targets.', + 'After all the targets are published, run the following command to merge the release branch:', ` $ craft publish ${newVersion} --target none\n`, ]; - logger.warn(msg.join("\n")); + logger.warn(msg.join('\n')); } // Run the post-release script diff --git a/src/commands/targets.ts b/src/commands/targets.ts index 1023623d..51113ae1 100644 --- a/src/commands/targets.ts +++ b/src/commands/targets.ts @@ -1,9 +1,9 @@ -import { getConfiguration } from "../config"; -import { formatJson } from "../utils/strings"; -import { getAllTargetNames, getTargetId } from "../targets"; +import { getConfiguration } from '../config'; +import { formatJson } from '../utils/strings'; +import { getAllTargetNames, getTargetId } from '../targets'; -export const command = ["targets"]; -export const description = "List defined targets as JSON array"; +export const command = ['targets']; +export const description = 'List defined targets as JSON array'; export function handler(): any { const definedTargets = getConfiguration().targets || []; diff --git a/src/config.ts b/src/config.ts index 0af2f5f9..0b29f42c 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,44 +1,44 @@ -import { existsSync, lstatSync, readFileSync } from "fs"; -import { dirname, join } from "path"; +import { existsSync, lstatSync, readFileSync } from 'fs'; +import { dirname, join } from 'path'; -import ajv from "ajv"; -import { safeLoad } from "js-yaml"; +import ajv from 'ajv'; +import { safeLoad } from 'js-yaml'; -import { logger } from "./logger"; +import { logger } from './logger'; import { CraftProjectConfig, GithubGlobalConfig, ArtifactProviderName, StatusProviderName, -} from "./schemas/project_config"; -import { ConfigurationError } from "./utils/errors"; +} from './schemas/project_config'; +import { ConfigurationError } from './utils/errors'; import { getPackageVersion, parseVersion, versionGreaterOrEqualThan, -} from "./utils/version"; -import { BaseArtifactProvider } from "./artifact_providers/base"; -import { GithubArtifactProvider } from "./artifact_providers/github"; -import { ZeusArtifactProvider } from "./artifact_providers/zeus"; -import { NoneArtifactProvider } from "./artifact_providers/none"; -import { GCSArtifactProvider } from "./artifact_providers/gcs"; +} from './utils/version'; +import { BaseArtifactProvider } from './artifact_providers/base'; +import { GithubArtifactProvider } from './artifact_providers/github'; +import { ZeusArtifactProvider } from './artifact_providers/zeus'; +import { NoneArtifactProvider } from './artifact_providers/none'; +import { GCSArtifactProvider } from './artifact_providers/gcs'; -import { ZeusStatusProvider } from "./status_providers/zeus"; -import { GithubStatusProvider } from "./status_providers/github"; -import { BaseStatusProvider } from "./status_providers/base"; +import { ZeusStatusProvider } from './status_providers/zeus'; +import { GithubStatusProvider } from './status_providers/github'; +import { BaseStatusProvider } from './status_providers/base'; // TODO support multiple configuration files (one per configuration) -export const CONFIG_FILE_NAME = ".craft.yml"; +export const CONFIG_FILE_NAME = '.craft.yml'; /** * The default prefix for the release branch. */ -export const DEFAULT_RELEASE_BRANCH_NAME = "release"; +export const DEFAULT_RELEASE_BRANCH_NAME = 'release'; /** * Epoch version for changing all defaults to GitHub */ -export const DEFAULTS_EPOCH_VERSION = "0.21.0"; +export const DEFAULTS_EPOCH_VERSION = '0.21.0'; /** * Cached path to the configuration file @@ -78,7 +78,7 @@ export function findConfigFile(): string | undefined { currentDir = parentDir; depth += 1; } - logger.warn("findConfigFile: Reached maximum allowed directory depth"); + logger.warn('findConfigFile: Reached maximum allowed directory depth'); return undefined; } @@ -114,7 +114,7 @@ export function getConfigFileDir(): string | undefined { * Reads JSON schema for project configuration */ export function getProjectConfigSchema(): any { - return require("./schemas/projectConfig.schema"); + return require('./schemas/projectConfig.schema'); } /** @@ -127,8 +127,8 @@ export function getProjectConfigSchema(): any { export function validateConfiguration( rawConfig: Record ): CraftProjectConfig { - logger.debug("Parsing and validating the configuration file..."); - const schemaName = "projectConfig"; + logger.debug('Parsing and validating the configuration file...'); + const schemaName = 'projectConfig'; const projectConfigSchema = getProjectConfigSchema(); const ajvValidator = new ajv().addSchema(projectConfigSchema, schemaName); const valid = ajvValidator.validate(schemaName, rawConfig); @@ -150,8 +150,8 @@ export function getConfiguration(): CraftProjectConfig { } const configPath = getConfigFilePath(); - logger.debug("Configuration file found: ", configPath); - const rawConfig = safeLoad(readFileSync(configPath, "utf-8")) as Record< + logger.debug('Configuration file found: ', configPath); + const rawConfig = safeLoad(readFileSync(configPath, 'utf-8')) as Record< string, any >; @@ -170,14 +170,14 @@ export function checkMinimalConfigVersion(): void { const minVersionRaw = config.minVersion; if (!minVersionRaw) { logger.debug( - "No minimal version specified in the configuration, skpipping the check" + 'No minimal version specified in the configuration, skpipping the check' ); return; } const currentVersionRaw = getPackageVersion(); if (!currentVersionRaw) { - throw new Error("Cannot get the current craft version"); + throw new Error('Cannot get the current craft version'); } const minVersion = parseVersion(minVersionRaw); @@ -232,16 +232,16 @@ export function getGlobalGithubConfig(): GithubGlobalConfig { if (!repoGithubConfig) { throw new ConfigurationError( - "GitHub configuration not found in the config file" + 'GitHub configuration not found in the config file' ); } if (!repoGithubConfig.owner) { - throw new ConfigurationError("GitHub target: owner not found"); + throw new ConfigurationError('GitHub target: owner not found'); } if (!repoGithubConfig.repo) { - throw new ConfigurationError("GitHub target: repo not found"); + throw new ConfigurationError('GitHub target: repo not found'); } return repoGithubConfig; @@ -252,8 +252,8 @@ export function getGlobalGithubConfig(): GithubGlobalConfig { */ export function getGitTagPrefix(): string { const targets = getConfiguration().targets || []; - const githubTarget = targets.find((target) => target.name === "github"); - return githubTarget?.tagPrefix || ""; + const githubTarget = targets.find((target) => target.name === 'github'); + return githubTarget?.tagPrefix || ''; } /** @@ -296,7 +296,7 @@ export function getArtifactProviderFromConfig(): BaseArtifactProvider { case ArtifactProviderName.Github: return new GithubArtifactProvider(artifactProviderConfig); default: { - throw new ConfigurationError("Invalid artifact provider"); + throw new ConfigurationError('Invalid artifact provider'); } } } @@ -345,7 +345,7 @@ export function getStatusProviderFromConfig(): BaseStatusProvider { statusProviderConfig ); default: { - throw new ConfigurationError("Invalid status provider"); + throw new ConfigurationError('Invalid status provider'); } } } diff --git a/src/index.ts b/src/index.ts index 99d7b1cf..42efd21c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,19 +1,19 @@ #!/usr/bin/env node -import once from "once"; -import yargs from "yargs"; +import once from 'once'; +import yargs from 'yargs'; -import { logger, init as initLogger } from "./logger"; -import { readEnvironmentConfig } from "./utils/env"; -import { isDryRun } from "./utils/helpers"; -import { hasNoInput, setNoInput } from "./utils/noInput"; -import { initSentrySdk } from "./utils/sentry"; -import { getPackageVersion } from "./utils/version"; +import { logger, init as initLogger } from './logger'; +import { readEnvironmentConfig } from './utils/env'; +import { isDryRun } from './utils/helpers'; +import { hasNoInput, setNoInput } from './utils/noInput'; +import { initSentrySdk } from './utils/sentry'; +import { getPackageVersion } from './utils/version'; // Commands -import * as prepare from "./commands/prepare"; -import * as publish from "./commands/publish"; -import * as targets from "./commands/targets"; -import * as artifacts from "./commands/artifacts"; +import * as prepare from './commands/prepare'; +import * as publish from './commands/publish'; +import * as targets from './commands/targets'; +import * as artifacts from './commands/artifacts'; /** * Handler for '--dry-run' option @@ -21,12 +21,12 @@ import * as artifacts from "./commands/artifacts"; function processDryRun(arg: T): T { // if the user explicitly set the flag on the command line, their choice // should override any previously set env var - if (process.argv.indexOf("--dry-run") > -1) { + if (process.argv.indexOf('--dry-run') > -1) { process.env.DRY_RUN = String(arg); } if (isDryRun()) { - logger.info("[dry-run] Dry-run mode is on!"); + logger.info('[dry-run] Dry-run mode is on!'); } return arg; @@ -40,7 +40,7 @@ function processNoInput(arg: T): T { setNoInput(true); } if (hasNoInput()) { - logger.debug("[no-input] The script will not accept any input!"); + logger.debug('[no-input] The script will not accept any input!'); } return arg; } @@ -49,7 +49,7 @@ function processNoInput(arg: T): T { * Prints the current version */ function printVersion(): void { - if (!process.argv.includes("-v") && !process.argv.includes("--version")) { + if (!process.argv.includes('-v') && !process.argv.includes('--version')) { // Print the current version logger.debug(`craft ${getPackageVersion()}`); } @@ -69,7 +69,7 @@ function main(): void { yargs .parserConfiguration({ - "boolean-negation": false, + 'boolean-negation': false, }) .command(prepare) .command(publish) @@ -77,23 +77,23 @@ function main(): void { .command(artifacts) .demandCommand() .version() - .alias("v", "version") + .alias('v', 'version') .help() - .alias("h", "help") - .option("no-input", { + .alias('h', 'help') + .option('no-input', { boolean: true, coerce: once(processNoInput), default: false, - describe: "Suppresses all user prompts", + describe: 'Suppresses all user prompts', }) - .global("no-input") - .option("dry-run", { + .global('no-input') + .option('dry-run', { boolean: true, coerce: once(processDryRun), default: false, - describe: "Dry run mode: do not perform any real actions", + describe: 'Dry run mode: do not perform any real actions', }) - .global("dry-run") + .global('dry-run') .strict() .showHelpOnFail(true) .parse(); diff --git a/src/logger.ts b/src/logger.ts index 0e6b6052..adabf02b 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,6 +1,6 @@ -import { addBreadcrumb, Severity } from "@sentry/node"; -import Table = require("cli-table"); -import consola = require("consola"); +import { addBreadcrumb, Severity } from '@sentry/node'; +import Table = require('cli-table'); +import consola = require('consola'); /** * Format a list as a table @@ -61,7 +61,7 @@ class SentryBreadcrumbReporter { * Read logging level from the environment and return the appropriate enum value */ function getLogLevelFromEnv(): LOG_LEVEL { - const logLevelName = (process.env.CRAFT_LOG_LEVEL || "").toUpperCase(); + const logLevelName = (process.env.CRAFT_LOG_LEVEL || '').toUpperCase(); const logLevelNumber = LOG_LEVEL[logLevelName as keyof typeof LOG_LEVEL]; return logLevelNumber ?? consola.level; } @@ -82,7 +82,7 @@ let initialized = false; */ export function init(logLevel?: LOG_LEVEL): Logger { if (initialized) { - consola.warn("Logger already initialized, ignoring duplicate init."); + consola.warn('Logger already initialized, ignoring duplicate init.'); } setLogLevel(logLevel !== undefined ? logLevel : getLogLevelFromEnv()); diff --git a/src/schemas/projectConfig.schema.ts b/src/schemas/projectConfig.schema.ts index 5e44e72f..c069c9e8 100644 --- a/src/schemas/projectConfig.schema.ts +++ b/src/schemas/projectConfig.schema.ts @@ -4,110 +4,110 @@ */ const projectConfigJsonSchema = { - title: "CraftProjectConfig", - description: "Craft project-specific configuration", - type: "object", + title: 'CraftProjectConfig', + description: 'Craft project-specific configuration', + type: 'object', properties: { github: { - title: "GithubGlobalConfig", - description: "Global (non-target!) GitHub configuration for the project", - type: "object", + title: 'GithubGlobalConfig', + description: 'Global (non-target!) GitHub configuration for the project', + type: 'object', properties: { owner: { - type: "string", + type: 'string', }, repo: { - type: "string", + type: 'string', }, }, additionalProperties: false, - required: ["owner", "repo"], + required: ['owner', 'repo'], }, targets: { - type: "array", - items: { $ref: "#/definitions/targetConfig" }, + type: 'array', + items: { $ref: '#/definitions/targetConfig' }, }, - preReleaseCommand: { type: "string" }, - postReleaseCommand: { type: "string" }, - releaseBranchPrefix: { type: "string" }, - changelog: { type: "string" }, + preReleaseCommand: { type: 'string' }, + postReleaseCommand: { type: 'string' }, + releaseBranchPrefix: { type: 'string' }, + changelog: { type: 'string' }, changelogPolicy: { - title: "ChangelogPolicy", - description: "Different policies for changelog management", - type: "string", - enum: ["auto", "simple", "none"], - tsEnumNames: ["Auto", "Simple", "None"], + title: 'ChangelogPolicy', + description: 'Different policies for changelog management', + type: 'string', + enum: ['auto', 'simple', 'none'], + tsEnumNames: ['Auto', 'Simple', 'None'], }, minVersion: { - type: "string", - pattern: "^\\d+\\.\\d+\\.\\d+.*$", + type: 'string', + pattern: '^\\d+\\.\\d+\\.\\d+.*$', }, requireNames: { - type: "array", - items: { type: "string" }, + type: 'array', + items: { type: 'string' }, }, statusProvider: { - title: "BaseStatusProvider", - description: "Which service should be used for status checks", - type: "object", + title: 'BaseStatusProvider', + description: 'Which service should be used for status checks', + type: 'object', properties: { name: { - title: "StatusProviderName", - description: "Name of the status provider", - type: "string", - enum: ["zeus", "github"], - tsEnumNames: ["Zeus", "Github"], + title: 'StatusProviderName', + description: 'Name of the status provider', + type: 'string', + enum: ['zeus', 'github'], + tsEnumNames: ['Zeus', 'Github'], }, config: { - type: "object", + type: 'object', }, }, additionalProperties: false, - required: ["name"], + required: ['name'], }, artifactProvider: { - title: "BaseArtifactProvider", - description: "Which service should be used for artifact storage", - type: "object", + title: 'BaseArtifactProvider', + description: 'Which service should be used for artifact storage', + type: 'object', properties: { name: { - title: "ArtifactProviderName", - description: "Name of the artifact provider", - type: "string", - enum: ["zeus", "gcs", "github", "none"], - tsEnumNames: ["Zeus", "GCS", "Github", "None"], + title: 'ArtifactProviderName', + description: 'Name of the artifact provider', + type: 'string', + enum: ['zeus', 'gcs', 'github', 'none'], + tsEnumNames: ['Zeus', 'GCS', 'Github', 'None'], }, config: { - type: "object", + type: 'object', }, }, additionalProperties: false, - required: ["name"], + required: ['name'], }, }, additionalProperties: false, - required: ["github"], + required: ['github'], definitions: { targetConfig: { - title: "TargetConfig", - description: "Generic target configuration", - type: "object", + title: 'TargetConfig', + description: 'Generic target configuration', + type: 'object', properties: { name: { - type: "string", + type: 'string', }, id: { - type: "string", + type: 'string', }, includeNames: { - type: "string", + type: 'string', }, excludeNames: { - type: "string", + type: 'string', }, }, - required: ["name"], + required: ['name'], }, /** @@ -132,36 +132,36 @@ const projectConfigJsonSchema = { * */ githubConfig: { - title: "GithubTargetConfig", - description: "Configuration options for the Github target", - extends: { $ref: "#/definitions/targetConfig" }, + title: 'GithubTargetConfig', + description: 'Configuration options for the Github target', + extends: { $ref: '#/definitions/targetConfig' }, properties: { changelog: { - type: "string", + type: 'string', }, - name: { type: "string", enum: ["github"] }, + name: { type: 'string', enum: ['github'] }, }, - required: ["name"], + required: ['name'], additionalProperties: false, }, npmConfig: { - title: "NpmTargetConfig", - description: "Configuration options for the NPM target", - extends: { $ref: "#/definitions/targetConfig" }, + title: 'NpmTargetConfig', + description: 'Configuration options for the NPM target', + extends: { $ref: '#/definitions/targetConfig' }, properties: { access: { - type: "string", + type: 'string', }, }, additionalProperties: false, }, cratesConfig: { - title: "CratesTargetConfig", - description: "Configuration options for the Crates target", - extends: { $ref: "#/definitions/targetConfig" }, + title: 'CratesTargetConfig', + description: 'Configuration options for the Crates target', + extends: { $ref: '#/definitions/targetConfig' }, properties: { noDevDeps: { - type: "boolean", + type: 'boolean', }, }, additionalProperties: false, diff --git a/src/schemas/project_config.ts b/src/schemas/project_config.ts index 4571f552..9a62a9e5 100644 --- a/src/schemas/project_config.ts +++ b/src/schemas/project_config.ts @@ -60,23 +60,23 @@ export interface BaseArtifactProvider { * Different policies for changelog management */ export const enum ChangelogPolicy { - Auto = "auto", - Simple = "simple", - None = "none", + Auto = 'auto', + Simple = 'simple', + None = 'none', } /** * Name of the status provider */ export const enum StatusProviderName { - Zeus = "zeus", - Github = "github", + Zeus = 'zeus', + Github = 'github', } /** * Name of the artifact provider */ export const enum ArtifactProviderName { - Zeus = "zeus", - GCS = "gcs", - Github = "github", - None = "none", + Zeus = 'zeus', + GCS = 'gcs', + Github = 'github', + None = 'none', } diff --git a/src/status_providers/base.ts b/src/status_providers/base.ts index a4dda205..8c62ae09 100644 --- a/src/status_providers/base.ts +++ b/src/status_providers/base.ts @@ -1,10 +1,10 @@ -import ora from "ora"; +import ora from 'ora'; -import { sleepAsync } from "../utils/system"; +import { sleepAsync } from '../utils/system'; -import { reportError } from "../utils/errors"; +import { reportError } from '../utils/errors'; -import { logger } from "../logger"; +import { logger } from '../logger'; /** Max number of seconds to wait for the build to finish */ const BUILD_STATUS_POLLING_MAX = 60 * 60; @@ -17,13 +17,13 @@ const BUILD_POLLING_INTERVAL = 30; */ export enum CommitStatus { /** Commit is still being tested/checked/etc. */ - PENDING = "pending", + PENDING = 'pending', /** All required commit checks have passed successfully */ - SUCCESS = "success", + SUCCESS = 'success', /** One or more commit checks failed */ - FAILURE = "failure", + FAILURE = 'failure', /** Commit could not be found */ - NOT_FOUND = "not_found", + NOT_FOUND = 'not_found', } /** Repository information */ @@ -55,7 +55,7 @@ export abstract class BaseStatusProvider { */ public async waitForTheBuildToSucceed(revision: string): Promise { // Status spinner - const spinner = ora({ spinner: "bouncingBar" }) as any; + const spinner = ora({ spinner: 'bouncingBar' }) as any; let secondsPassed = 0; let firstIteration = true; @@ -104,8 +104,8 @@ export abstract class BaseStatusProvider { // Format as "YYYY-MM-DD hh:mm:ss" const timeString = new Date() .toISOString() - .replace(/T/, " ") - .replace(/\..+/, ""); + .replace(/T/, ' ') + .replace(/\..+/, ''); // Update the spinner const waitMessage = `[${timeString}] CI builds are still in progress, sleeping for ${BUILD_POLLING_INTERVAL} seconds...`; spinner.text = waitMessage; diff --git a/src/status_providers/github.ts b/src/status_providers/github.ts index 5168b0f8..9f6cbf0f 100644 --- a/src/status_providers/github.ts +++ b/src/status_providers/github.ts @@ -1,10 +1,10 @@ -import * as Github from "@octokit/rest"; +import * as Github from '@octokit/rest'; -import { logger } from "../logger"; -import { BaseStatusProvider, CommitStatus, RepositoryInfo } from "./base"; -import { getGithubClient } from "../utils/githubApi"; -import { ConfigurationError } from "../utils/errors"; -import { formatJson } from "../utils/strings"; +import { logger } from '../logger'; +import { BaseStatusProvider, CommitStatus, RepositoryInfo } from './base'; +import { getGithubClient } from '../utils/githubApi'; +import { ConfigurationError } from '../utils/errors'; +import { formatJson } from '../utils/strings'; /** * Status provider that talks to GitHub to get commit checks (statuses) @@ -74,34 +74,34 @@ export class GithubStatusProvider extends BaseStatusProvider { return contextResult; } } - logger.debug("All contexts concluded successfully!"); + logger.debug('All contexts concluded successfully!'); return CommitStatus.SUCCESS; } else { logger.debug( - "No config provided for Github status provider, calculating the combined status..." + 'No config provided for Github status provider, calculating the combined status...' ); let commitApiStatusResult; if ( revisionStatus.total_count === 0 && - revisionStatus.state === "pending" + revisionStatus.state === 'pending' ) { // Edge case, this is what GitHub returns when there are no registered legacy checks. - logger.debug("No legacy checks detected, checking for runs..."); + logger.debug('No legacy checks detected, checking for runs...'); const hasPendingActiveSuites = revisionCheckSuites.check_suites.some( (suite) => // Need the any cast as octokit lacks this prop in its types (suite as any).latest_check_runs_count > 0 && - suite.status === "queued" + suite.status === 'queued' ); if (revisionChecks.total_count > 0) { - logger.debug("Check runs exist, continuing..."); + logger.debug('Check runs exist, continuing...'); commitApiStatusResult = CommitStatus.SUCCESS; } else if (hasPendingActiveSuites) { - logger.debug("Pending check suites exist, continuing..."); + logger.debug('Pending check suites exist, continuing...'); commitApiStatusResult = CommitStatus.PENDING; } else { - logger.warn("No valid build contexts detected, did any checks run?"); + logger.warn('No valid build contexts detected, did any checks run?'); commitApiStatusResult = CommitStatus.NOT_FOUND; } } else { @@ -156,10 +156,10 @@ export class GithubStatusProvider extends BaseStatusProvider { logger.debug(`Status check results: ${formatJson(results)}`); if (results.includes(CommitStatus.FAILURE)) { - logger.error("At least one of the checks has failed, result: FAILURE"); + logger.error('At least one of the checks has failed, result: FAILURE'); return CommitStatus.FAILURE; } else if (results.includes(CommitStatus.PENDING)) { - logger.debug("At least one of the checks is pending, result: PENDING"); + logger.debug('At least one of the checks is pending, result: PENDING'); return CommitStatus.PENDING; } else if ( results[0] === CommitStatus.NOT_FOUND && @@ -171,7 +171,7 @@ export class GithubStatusProvider extends BaseStatusProvider { logger.debug(`Context "${context}" was build succesffully!`); return CommitStatus.SUCCESS; } else { - throw new Error("Unreachable"); + throw new Error('Unreachable'); } } @@ -181,9 +181,9 @@ export class GithubStatusProvider extends BaseStatusProvider { * @param state Status string */ private stateToCommitStatus(state: string): CommitStatus { - if (state === "success") { + if (state === 'success') { return CommitStatus.SUCCESS; - } else if (state === "pending") { + } else if (state === 'pending') { return CommitStatus.PENDING; } else { return CommitStatus.FAILURE; @@ -229,15 +229,15 @@ export class GithubStatusProvider extends BaseStatusProvider { let isSomethingPending = revisionCheckSuites.check_suites.some( (suite) => // Need the any cast as octokit lacks this prop in its types - (suite as any).latest_check_runs_count > 0 && suite.status === "queued" + (suite as any).latest_check_runs_count > 0 && suite.status === 'queued' ); let found = false; for (const run of revisionChecks.check_runs) { if (context && run.name !== context) { continue; } - if (run.status === "completed") { - if (run.conclusion !== "success" && run.conclusion !== "skipped") { + if (run.status === 'completed') { + if (run.conclusion !== 'success' && run.conclusion !== 'skipped') { return CommitStatus.FAILURE; } } else { diff --git a/src/status_providers/zeus.ts b/src/status_providers/zeus.ts index dd719347..f396668d 100644 --- a/src/status_providers/zeus.ts +++ b/src/status_providers/zeus.ts @@ -1,5 +1,5 @@ -import { BaseStatusProvider, CommitStatus, RepositoryInfo } from "./base"; -import { ZeusStore } from "../stores/zeus"; +import { BaseStatusProvider, CommitStatus, RepositoryInfo } from './base'; +import { ZeusStore } from '../stores/zeus'; /** * TODO @@ -28,7 +28,7 @@ export class ZeusStatusProvider extends BaseStatusProvider { try { zeusRevision = await this.store.getRevision(revision); } catch (e) { - const errorMessage: string = e.message || ""; + const errorMessage: string = e.message || ''; if (errorMessage.match(/404 not found|resource not found/i)) { return CommitStatus.NOT_FOUND; } diff --git a/src/stores/__tests__/zeus.test.ts b/src/stores/__tests__/zeus.test.ts index 0e6a1eef..16027335 100644 --- a/src/stores/__tests__/zeus.test.ts +++ b/src/stores/__tests__/zeus.test.ts @@ -1,8 +1,8 @@ -import { Artifact, Status } from "@zeus-ci/sdk"; +import { Artifact, Status } from '@zeus-ci/sdk'; -jest.mock("../../utils/env"); +jest.mock('../../utils/env'); -import { ZeusStore } from "../zeus"; +import { ZeusStore } from '../zeus'; // TODO (kmclb) move these tests over to the artifact provider test folder @@ -11,92 +11,92 @@ function artifactFactory( options?: Record ): Artifact { return { - download_url: "http://invalid", + download_url: 'http://invalid', file: { - name: "test", + name: 'test', size: 100, }, id: name, name, status: Status.FINISHED, - type: "test/test", + type: 'test/test', ...options, }; } -const REPO_OWNER = "craft-test-owner"; -const REPO_NAME = "craft-test"; +const REPO_OWNER = 'craft-test-owner'; +const REPO_NAME = 'craft-test'; -describe("filterArtifactsForRevision", () => { +describe('filterArtifactsForRevision', () => { const zeusStore = new ZeusStore(REPO_OWNER, REPO_NAME); const artifactList = [ - "test1.zip", - "test2.exe", - "test3.tgz", - "smthelse", + 'test1.zip', + 'test2.exe', + 'test3.tgz', + 'smthelse', ].map((name) => artifactFactory(name, undefined)); zeusStore.listArtifactsForRevision = jest.fn( async (_revision) => artifactList ); - const revision = "1234567"; + const revision = '1234567'; beforeEach(() => { jest.clearAllMocks(); }); - test("does not change the list if no arguments provided", async () => { + test('does not change the list if no arguments provided', async () => { const filtered = await zeusStore.filterArtifactsForRevision(revision); expect(filtered).toBe(artifactList); }); - test("uses includeNames", async () => { + test('uses includeNames', async () => { const filtered = await zeusStore.filterArtifactsForRevision(revision, { includeNames: /.exe$/, }); - expect(filtered).toEqual([artifactFactory("test2.exe")]); + expect(filtered).toEqual([artifactFactory('test2.exe')]); }); - test("uses excludeNames", async () => { + test('uses excludeNames', async () => { const filtered = await zeusStore.filterArtifactsForRevision(revision, { excludeNames: /^test.*$/, }); - expect(filtered).toEqual([artifactFactory("smthelse")]); + expect(filtered).toEqual([artifactFactory('smthelse')]); }); - test("uses both includeNames and excludeNames", async () => { + test('uses both includeNames and excludeNames', async () => { const filtered = await zeusStore.filterArtifactsForRevision(revision, { excludeNames: /(exe|zip)$/, includeNames: /^test/, }); - expect(filtered).toEqual([artifactFactory("test3.tgz")]); + expect(filtered).toEqual([artifactFactory('test3.tgz')]); }); }); -describe("filterArtifactsForRevision", () => { +describe('filterArtifactsForRevision', () => { const zeusStore = new ZeusStore(REPO_OWNER, REPO_NAME); const artifactList = [ - "test1.zip", - "test2.exe", - "test3.tgz", - "smthelse", + 'test1.zip', + 'test2.exe', + 'test3.tgz', + 'smthelse', ].map((name) => artifactFactory(name, undefined)); zeusStore.client.listArtifactsForRevision = jest .fn() .mockReturnValue(artifactList); const mockClientListArtifacts = zeusStore.client .listArtifactsForRevision as jest.Mock; - const revision = "1234567"; + const revision = '1234567'; beforeEach(() => { jest.clearAllMocks(); zeusStore.clearStoreCaches(); }); - test("calls Zeus client with proper arguments", async () => { + test('calls Zeus client with proper arguments', async () => { const result = await zeusStore.listArtifactsForRevision(revision); expect(result).toEqual(artifactList); @@ -107,7 +107,7 @@ describe("filterArtifactsForRevision", () => { ); }); - test("caches results", async () => { + test('caches results', async () => { const result1 = await zeusStore.listArtifactsForRevision(revision); const result2 = await zeusStore.listArtifactsForRevision(revision); @@ -115,20 +115,20 @@ describe("filterArtifactsForRevision", () => { expect(mockClientListArtifacts).toHaveBeenCalledTimes(1); }); - test("picks only the most recent artifact in case there are duplicated names", async () => { - const name = "file.zip"; + test('picks only the most recent artifact in case there are duplicated names', async () => { + const name = 'file.zip'; const artifacts = [ artifactFactory(name, { - id: "1", - updated_at: "2018-01-01T00:00:10.000000+00:00", + id: '1', + updated_at: '2018-01-01T00:00:10.000000+00:00', }), artifactFactory(name, { - id: "2", - updated_at: "2018-11-11T00:55:55.999999+00:00", + id: '2', + updated_at: '2018-11-11T00:55:55.999999+00:00', }), artifactFactory(name, { - id: "3", - updated_at: "invalid", + id: '3', + updated_at: 'invalid', }), ]; mockClientListArtifacts.mockReturnValue(artifacts); diff --git a/src/stores/zeus.ts b/src/stores/zeus.ts index ee06c5d9..586a4f1b 100644 --- a/src/stores/zeus.ts +++ b/src/stores/zeus.ts @@ -5,17 +5,17 @@ import { RevisionInfo, Status, RepositoryInfo, -} from "@zeus-ci/sdk"; -import * as _ from "lodash"; +} from '@zeus-ci/sdk'; +import * as _ from 'lodash'; -import { checkEnvForPrerequisite } from "../utils/env"; +import { checkEnvForPrerequisite } from '../utils/env'; import { calculateChecksum, HashAlgorithm, HashOutputFormat, -} from "../utils/system"; -import { clearObjectProperties } from "../utils/objects"; -import { logger } from "../logger"; +} from '../utils/system'; +import { clearObjectProperties } from '../utils/objects'; +import { logger } from '../logger'; // TODO (kmclb) get rid of this file once artifact providers are done @@ -66,8 +66,8 @@ export class ZeusStore { downloadDirectory?: string ) { checkEnvForPrerequisite({ - legacyName: "ZEUS_TOKEN", - name: "ZEUS_API_TOKEN", + legacyName: 'ZEUS_TOKEN', + name: 'ZEUS_API_TOKEN', }); // We currently need ZEUS_TOKEN set for zeus-sdk to work properly if (!process.env.ZEUS_TOKEN) { @@ -150,7 +150,7 @@ export class ZeusStore { // Sort by the update time const sortedArtifacts = _.sortBy( artifactObjects, - (artifact) => Date.parse(artifact.updated_at || "") || 0 + (artifact) => Date.parse(artifact.updated_at || '') || 0 ); return sortedArtifacts[sortedArtifacts.length - 1]; } diff --git a/src/targets/__tests__/awsLambda.test.ts b/src/targets/__tests__/awsLambda.test.ts index d33071f4..01c856ea 100644 --- a/src/targets/__tests__/awsLambda.test.ts +++ b/src/targets/__tests__/awsLambda.test.ts @@ -1,39 +1,39 @@ -import { NoneArtifactProvider } from "../../artifact_providers/none"; -import { ConfigurationError } from "../../utils/errors"; -import { AwsLambdaLayerTarget } from "../awsLambdaLayer"; +import { NoneArtifactProvider } from '../../artifact_providers/none'; +import { ConfigurationError } from '../../utils/errors'; +import { AwsLambdaLayerTarget } from '../awsLambdaLayer'; -jest.mock("fs"); +jest.mock('fs'); /** Returns a new AwsLambdaLayerTarget test instance. */ function getAwsLambdaTarget(): AwsLambdaLayerTarget { return new AwsLambdaLayerTarget( { - name: "aws-lambda-layer", - ["testKey"]: "testValue", + name: 'aws-lambda-layer', + ['testKey']: 'testValue', }, new NoneArtifactProvider() ); } function setAwsEnvironmentVariables() { - process.env.AWS_ACCESS_KEY_ID = "test aws access key"; - process.env.AWS_SECRET_ACCESS_KEY = "test aws secret access key"; - process.env.GITHUB_TOKEN = "test github token"; - process.env.GITHUB_API_TOKEN = "test github api token"; + process.env.AWS_ACCESS_KEY_ID = 'test aws access key'; + process.env.AWS_SECRET_ACCESS_KEY = 'test aws secret access key'; + process.env.GITHUB_TOKEN = 'test github token'; + process.env.GITHUB_API_TOKEN = 'test github api token'; } function setTestingProjectConfig(awsTarget: AwsLambdaLayerTarget) { - awsTarget.config.layerName = "testLayerName"; + awsTarget.config.layerName = 'testLayerName'; awsTarget.config.compatibleRuntimes = [ { - name: "runtimeTestName", - versions: ["nodejs10.x", "nodejs12.x"], + name: 'runtimeTestName', + versions: ['nodejs10.x', 'nodejs12.x'], }, ]; - awsTarget.config.license = "MIT"; + awsTarget.config.license = 'MIT'; } -describe("get aws config environment variables", () => { +describe('get aws config environment variables', () => { const oldEnvVariables = process.env; beforeEach(() => { @@ -46,15 +46,15 @@ describe("get aws config environment variables", () => { }); function deleteTargetOptionsFromEnvironment() { - if ("AWS_ACCESS_KEY_ID" in process.env) { + if ('AWS_ACCESS_KEY_ID' in process.env) { delete process.env.AWS_ACCESS_KEY_ID; } - if ("AWS_SECRET_ACCESES_KEY" in process.env) { + if ('AWS_SECRET_ACCESES_KEY' in process.env) { delete process.env.AWS_SECRET_ACCESES_KEY; } } - test("errors on missing environment variables", () => { + test('errors on missing environment variables', () => { deleteTargetOptionsFromEnvironment(); try { getAwsLambdaTarget(); @@ -63,7 +63,7 @@ describe("get aws config environment variables", () => { } }); - test("success on environment variables", () => { + test('success on environment variables', () => { deleteTargetOptionsFromEnvironment(); setAwsEnvironmentVariables(); // AwsLambdaTarget needs the environment variables to initialize. @@ -71,7 +71,7 @@ describe("get aws config environment variables", () => { }); }); -describe("project config parameters", () => { +describe('project config parameters', () => { beforeAll(() => { setAwsEnvironmentVariables(); }); @@ -82,11 +82,11 @@ describe("project config parameters", () => { delete awsTarget.config.license; } - test("missing config parameters", async () => { + test('missing config parameters', async () => { const awsTarget = getAwsLambdaTarget(); clearConfig(awsTarget); try { - await awsTarget.publish("", ""); + await awsTarget.publish('', ''); } catch (error) { expect(error instanceof ConfigurationError).toBe(true); expect( @@ -95,10 +95,10 @@ describe("project config parameters", () => { } }); - test("correct config", async () => { + test('correct config', async () => { const awsTarget = getAwsLambdaTarget(); setTestingProjectConfig(awsTarget); - const failingTestErrorMsg = "failing mock test"; + const failingTestErrorMsg = 'failing mock test'; const getArtifactsFailingMock = jest.fn().mockImplementation(() => { throw new Error(failingTestErrorMsg); }); @@ -111,15 +111,15 @@ describe("project config parameters", () => { awsTarget.getArtifactsForRevision = getArtifactsFailingMock.bind( AwsLambdaLayerTarget ); - await awsTarget.publish("", ""); // Should break the mocked function. - fail("Should not reach here"); + await awsTarget.publish('', ''); // Should break the mocked function. + fail('Should not reach here'); } catch (error) { expect(new RegExp(failingTestErrorMsg).test(error.message)).toBe(true); } }); }); -describe("publish", () => { +describe('publish', () => { beforeAll(() => { setAwsEnvironmentVariables(); }); @@ -128,7 +128,7 @@ describe("publish", () => { return []; }); - test("error on missing artifact", async () => { + test('error on missing artifact', async () => { const awsTarget = getAwsLambdaTarget(); setTestingProjectConfig(awsTarget); awsTarget.getArtifactsForRevision = noArtifactsForRevision.bind( @@ -138,7 +138,7 @@ describe("publish", () => { // thrown; when it's on dry run, the error is logged and `undefined` is // returned. Thus, both alternatives have been considered. try { - const noPackageFound = await awsTarget.publish("version", "revision"); + const noPackageFound = await awsTarget.publish('version', 'revision'); expect(noPackageFound).toBe(undefined); } catch (error) { expect(error instanceof Error).toBe(true); @@ -148,10 +148,10 @@ describe("publish", () => { }); const twoArtifactsForRevision = jest.fn().mockImplementation(function () { - return ["file1", "file2"]; + return ['file1', 'file2']; }); - test("error on having too many artifacts", async () => { + test('error on having too many artifacts', async () => { const awsTarget = getAwsLambdaTarget(); setTestingProjectConfig(awsTarget); awsTarget.getArtifactsForRevision = twoArtifactsForRevision.bind( @@ -162,8 +162,8 @@ describe("publish", () => { // returned. Thus, both alternatives have been considered. try { const multiplePackagesFound = await awsTarget.publish( - "version", - "revision" + 'version', + 'revision' ); expect(multiplePackagesFound).toBe(undefined); } catch (error) { diff --git a/src/targets/__tests__/crates.test.ts b/src/targets/__tests__/crates.test.ts index 33b5a4f5..f44c9a20 100644 --- a/src/targets/__tests__/crates.test.ts +++ b/src/targets/__tests__/crates.test.ts @@ -1,15 +1,15 @@ -import { CrateDependency, CratePackage, CratesTarget } from "../crates"; -import { NoneArtifactProvider } from "../../artifact_providers/none"; +import { CrateDependency, CratePackage, CratesTarget } from '../crates'; +import { NoneArtifactProvider } from '../../artifact_providers/none'; -jest.mock("../../utils/system"); +jest.mock('../../utils/system'); function cratePackageFactory(name: string): CratePackage { return { dependencies: [], id: name, - manifest_path: "", + manifest_path: '', name, - version: "1.0.0", + version: '1.0.0', publish: null, }; } @@ -17,7 +17,7 @@ function cratePackageFactory(name: string): CratePackage { function cratePackageToDependency(cratePackage: CratePackage): CrateDependency { return { name: cratePackage.name, - req: "1.0.0", + req: '1.0.0', kind: null, }; } @@ -25,22 +25,22 @@ function cratePackageToDependency(cratePackage: CratePackage): CrateDependency { function makeDev(dependency: CrateDependency): CrateDependency { return { ...dependency, - kind: "dev", + kind: 'dev', }; } -describe("getPublishOrder", () => { - process.env.CRATES_IO_TOKEN = "xxx"; +describe('getPublishOrder', () => { + process.env.CRATES_IO_TOKEN = 'xxx'; const target = new CratesTarget( { - name: "crates", + name: 'crates', noDevDeps: true, }, new NoneArtifactProvider() ); - test("sorts crate packages properly", () => { - const packages = ["p1", "p2", "p3", "p4"].map(cratePackageFactory); + test('sorts crate packages properly', () => { + const packages = ['p1', 'p2', 'p3', 'p4'].map(cratePackageFactory); const [p1, p2, p3, p4] = packages; p1.dependencies = [p2, p3].map(cratePackageToDependency); p3.dependencies = [p4].map(cratePackageToDependency); @@ -49,13 +49,13 @@ describe("getPublishOrder", () => { expect(target.getPublishOrder(packages)).toEqual(sortedPackages); }); - test("does not fail on a single package", () => { - const packages = [cratePackageFactory("p1")]; + test('does not fail on a single package', () => { + const packages = [cratePackageFactory('p1')]; expect(target.getPublishOrder(packages)).toEqual(packages); }); - test("errors on circular dependencies", () => { - const packages = ["p1", "p2"].map(cratePackageFactory); + test('errors on circular dependencies', () => { + const packages = ['p1', 'p2'].map(cratePackageFactory); const [p1, p2] = packages; p1.dependencies = [cratePackageToDependency(p2)]; @@ -64,8 +64,8 @@ describe("getPublishOrder", () => { expect(() => target.getPublishOrder(packages)).toThrowError(Error); }); - test("excludes dev dependencies", () => { - const packages = ["p1", "p2"].map(cratePackageFactory); + test('excludes dev dependencies', () => { + const packages = ['p1', 'p2'].map(cratePackageFactory); const [p1, p2] = packages; p1.dependencies = [cratePackageToDependency(p2)]; diff --git a/src/targets/__tests__/index.test.ts b/src/targets/__tests__/index.test.ts index 2d773e7f..85efc3b3 100644 --- a/src/targets/__tests__/index.test.ts +++ b/src/targets/__tests__/index.test.ts @@ -1,14 +1,14 @@ -import { getAllTargetNames, getTargetByName } from ".."; -import { GithubTarget } from "../github"; +import { getAllTargetNames, getTargetByName } from '..'; +import { GithubTarget } from '../github'; -describe("getTargetByName", () => { - test("converts target name to class", () => { - expect(getTargetByName("github")).toBe(GithubTarget); +describe('getTargetByName', () => { + test('converts target name to class', () => { + expect(getTargetByName('github')).toBe(GithubTarget); }); }); -describe("getAllTargetNames", () => { - test("retrieves all target names", () => { - expect(getAllTargetNames()).toContain("github"); +describe('getAllTargetNames', () => { + test('retrieves all target names', () => { + expect(getAllTargetNames()).toContain('github'); }); }); diff --git a/src/targets/awsLambdaLayer.ts b/src/targets/awsLambdaLayer.ts index 92fbaabc..eb530413 100644 --- a/src/targets/awsLambdaLayer.ts +++ b/src/targets/awsLambdaLayer.ts @@ -1,32 +1,32 @@ -import * as fs from "fs"; -import * as path from "path"; +import * as fs from 'fs'; +import * as path from 'path'; -import * as Github from "@octokit/rest"; -import simpleGit from "simple-git"; +import * as Github from '@octokit/rest'; +import simpleGit from 'simple-git'; import { getAuthUsername, getGithubApiToken, getGithubClient, GithubRemote, -} from "../utils/githubApi"; +} from '../utils/githubApi'; -import { logger as loggerRaw } from "../logger"; -import { TargetConfig } from "../schemas/project_config"; -import { BaseTarget } from "./base"; -import { BaseArtifactProvider } from "../artifact_providers/base"; -import { ConfigurationError, reportError } from "../utils/errors"; +import { logger as loggerRaw } from '../logger'; +import { TargetConfig } from '../schemas/project_config'; +import { BaseTarget } from './base'; +import { BaseArtifactProvider } from '../artifact_providers/base'; +import { ConfigurationError, reportError } from '../utils/errors'; import { AwsLambdaLayerManager, CompatibleRuntime, extractRegionNames, getAccountFromArn, getRegionsFromAws, -} from "../utils/awsLambdaLayerManager"; -import { createSymlinks } from "../utils/symlink"; -import { withTempDir } from "../utils/files"; -import { isDryRun } from "../utils/helpers"; -import { isPreviewRelease } from "../utils/version"; -import { getRegistryGithubRemote } from "../utils/registry"; +} from '../utils/awsLambdaLayerManager'; +import { createSymlinks } from '../utils/symlink'; +import { withTempDir } from '../utils/files'; +import { isDryRun } from '../utils/helpers'; +import { isPreviewRelease } from '../utils/version'; +import { getRegistryGithubRemote } from '../utils/registry'; const logger = loggerRaw.withScope(`[aws-lambda-layer]`); @@ -49,15 +49,15 @@ interface AwsLambdaTargetConfig { */ export class AwsLambdaLayerTarget extends BaseTarget { /** Target name */ - public readonly name: string = "aws-lambda-layer"; + public readonly name: string = 'aws-lambda-layer'; /** Target options */ public readonly awsLambdaConfig: AwsLambdaTargetConfig; /** GitHub client. */ public readonly github: Github; /** The directory where the runtime-specific directories are. */ - private readonly AWS_REGISTRY_DIR = "aws-lambda-layers"; + private readonly AWS_REGISTRY_DIR = 'aws-lambda-layers'; /** File containing data fields every new version file overrides */ - private readonly BASE_FILENAME = "base.json"; + private readonly BASE_FILENAME = 'base.json'; public constructor( config: TargetConfig, @@ -93,18 +93,18 @@ export class AwsLambdaLayerTarget extends BaseTarget { */ private checkProjectConfig(): void { const missingConfigOptions = []; - if (!("layerName" in this.config)) { - missingConfigOptions.push("layerName"); + if (!('layerName' in this.config)) { + missingConfigOptions.push('layerName'); } - if (!("compatibleRuntimes" in this.config)) { - missingConfigOptions.push("compatibleRuntimes"); + if (!('compatibleRuntimes' in this.config)) { + missingConfigOptions.push('compatibleRuntimes'); } - if (!("license" in this.config)) { - missingConfigOptions.push("license"); + if (!('license' in this.config)) { + missingConfigOptions.push('license'); } if (missingConfigOptions.length > 0) { throw new ConfigurationError( - "Missing project configuration parameter(s): " + missingConfigOptions + 'Missing project configuration parameter(s): ' + missingConfigOptions ); } } @@ -117,7 +117,7 @@ export class AwsLambdaLayerTarget extends BaseTarget { public async publish(version: string, revision: string): Promise { this.checkProjectConfig(); - logger.debug("Fetching artifact list..."); + logger.debug('Fetching artifact list...'); const packageFiles = await this.getArtifactsForRevision(revision, { includeNames: this.config.includeNames === undefined @@ -126,13 +126,13 @@ export class AwsLambdaLayerTarget extends BaseTarget { }); if (packageFiles.length == 0) { - reportError("Cannot publish AWS Lambda Layer: no packages found"); + reportError('Cannot publish AWS Lambda Layer: no packages found'); return undefined; } else if (packageFiles.length > 1) { reportError( - "Cannot publish AWS Lambda Layer: " + - "multiple packages with matching patterns were found. You may want " + - "to include or modify the includeNames parameter in the project config" + 'Cannot publish AWS Lambda Layer: ' + + 'multiple packages with matching patterns were found. You may want ' + + 'to include or modify the includeNames parameter in the project config' ); return undefined; } @@ -142,7 +142,7 @@ export class AwsLambdaLayerTarget extends BaseTarget { ); const awsRegions = extractRegionNames(await getRegionsFromAws()); - logger.debug("AWS regions: " + awsRegions); + logger.debug('AWS regions: ' + awsRegions); const remote = this.awsLambdaConfig.registryRemote; const username = await getAuthUsername(this.github); @@ -161,30 +161,30 @@ export class AwsLambdaLayerTarget extends BaseTarget { awsRegions, artifactBuffer ); - logger.debug("Finished publishing runtimes."); + logger.debug('Finished publishing runtimes.'); } else { - logger.info("[dry-run] Not publishing new layers."); + logger.info('[dry-run] Not publishing new layers.'); } - await git.add(["."]); - await git.checkout("master"); + await git.add(['.']); + await git.checkout('master'); const runtimeNames = this.config.compatibleRuntimes.map( (runtime: CompatibleRuntime) => runtime.name ); await git.commit( - "craft(aws-lambda): AWS Lambda layers published\n\n" + + 'craft(aws-lambda): AWS Lambda layers published\n\n' + `v${version} for ${runtimeNames}` ); if ( isPushableToRegistry(version, this.awsLambdaConfig.linkPrereleases) ) { - logger.info("Pushing changes..."); + logger.info('Pushing changes...'); await git.push(); } }, true, - "craft-release-awslambdalayer-" + 'craft-release-awslambdalayer-' ); } @@ -215,7 +215,7 @@ export class AwsLambdaLayerTarget extends BaseTarget { let publishedLayers = []; try { publishedLayers = await layerManager.publishToAllRegions(); - logger.debug("Finished publishing to all regions."); + logger.debug('Finished publishing to all regions.'); } catch (error) { logger.error( `Did not publish layers for ${runtime.name}. ` + @@ -302,11 +302,11 @@ function createVersionSymlinks( versionFilepath: string ): void { logger.debug(`Creating symlinks...`); - const latestVersionPath = path.posix.join(directory, "latest.json"); + const latestVersionPath = path.posix.join(directory, 'latest.json'); if (fs.existsSync(latestVersionPath)) { const previousVersion = fs .readlinkSync(latestVersionPath) - .split(".json")[0]; + .split('.json')[0]; createSymlinks(versionFilepath, version, previousVersion); } else { // When no previous versions are found, just create symlinks. @@ -330,7 +330,7 @@ function isPushableToRegistry( linkPrereleases: boolean ): boolean { if (isDryRun()) { - logger.info("[dry-run] Not pushing the branch."); + logger.info('[dry-run] Not pushing the branch.'); return false; } if (isPreviewRelease(version) && !linkPrereleases) { diff --git a/src/targets/base.ts b/src/targets/base.ts index 97a00e6e..67288386 100644 --- a/src/targets/base.ts +++ b/src/targets/base.ts @@ -1,11 +1,11 @@ -import { logger } from "../logger"; -import { TargetConfig } from "../schemas/project_config"; -import { FilterOptions } from "../stores/zeus"; -import { stringToRegexp } from "../utils/filters"; +import { logger } from '../logger'; +import { TargetConfig } from '../schemas/project_config'; +import { FilterOptions } from '../stores/zeus'; +import { stringToRegexp } from '../utils/filters'; import { BaseArtifactProvider, RemoteArtifact, -} from "../artifact_providers/base"; +} from '../artifact_providers/base'; // TODO: make abstract? /** @@ -13,7 +13,7 @@ import { */ export class BaseTarget { /** Target name */ - public readonly name: string = "base"; + public readonly name: string = 'base'; /** Artifact provider */ public readonly artifactProvider: BaseArtifactProvider; /** Unparsed target configuration */ @@ -47,7 +47,7 @@ export class BaseTarget { * @param revision Git commit SHA to be published */ public async publish(_version: string, _revision: string): Promise { - throw new Error("Not implemented"); + throw new Error('Not implemented'); return; } @@ -69,7 +69,7 @@ export class BaseTarget { }; // This is a hacky legacy way of skipping artifact downloads. // Can be removed when we fully migrate from ZeusStore to artifact providers. - if (filterOptions.includeNames?.source === "none") { + if (filterOptions.includeNames?.source === 'none') { logger.debug( `target.includeNames is 'none', skipping artifacts downloads.` ); diff --git a/src/targets/brew.ts b/src/targets/brew.ts index 985f72ab..d52f03b6 100644 --- a/src/targets/brew.ts +++ b/src/targets/brew.ts @@ -1,21 +1,21 @@ -import { mapLimit } from "async"; -import * as Github from "@octokit/rest"; - -import { getGlobalGithubConfig } from "../config"; -import { logger as loggerRaw } from "../logger"; -import { GithubGlobalConfig, TargetConfig } from "../schemas/project_config"; -import { ConfigurationError } from "../utils/errors"; -import { getGithubClient } from "../utils/githubApi"; -import { isDryRun } from "../utils/helpers"; -import { renderTemplateSafe } from "../utils/strings"; -import { HashAlgorithm, HashOutputFormat } from "../utils/system"; -import { BaseTarget } from "./base"; +import { mapLimit } from 'async'; +import * as Github from '@octokit/rest'; + +import { getGlobalGithubConfig } from '../config'; +import { logger as loggerRaw } from '../logger'; +import { GithubGlobalConfig, TargetConfig } from '../schemas/project_config'; +import { ConfigurationError } from '../utils/errors'; +import { getGithubClient } from '../utils/githubApi'; +import { isDryRun } from '../utils/helpers'; +import { renderTemplateSafe } from '../utils/strings'; +import { HashAlgorithm, HashOutputFormat } from '../utils/system'; +import { BaseTarget } from './base'; import { BaseArtifactProvider, MAX_DOWNLOAD_CONCURRENCY, -} from "../artifact_providers/base"; +} from '../artifact_providers/base'; -const logger = loggerRaw.withScope("[brew]"); +const logger = loggerRaw.withScope('[brew]'); /** * Regex used to parse homebrew taps (github repositories) @@ -47,7 +47,7 @@ export interface BrewTargetOptions { */ export class BrewTarget extends BaseTarget { /** Target name */ - public readonly name: string = "brew"; + public readonly name: string = 'brew'; /** Target options */ public readonly brewConfig: BrewTargetOptions; /** Github client */ @@ -97,8 +97,8 @@ export class BrewTarget extends BaseTarget { const { tap } = this.config; if (!tap) { return { - owner: "homebrew", - repo: "homebrew-core", + owner: 'homebrew', + repo: 'homebrew-core', }; } @@ -161,7 +161,7 @@ export class BrewTarget extends BaseTarget { // Format checksums and the tag version into the formula file const filesList = await this.getArtifactsForRevision(revision); logger.debug( - "Downloading artifacts for the revision:", + 'Downloading artifacts for the revision:', JSON.stringify(filesList.map((file) => file.filename)) ); @@ -185,17 +185,17 @@ export class BrewTarget extends BaseTarget { // Try to find the repository to publish in if (tapRepo.owner !== owner) { // TODO: Create a PR if we have no push rights to this repo - logger.warn("Skipping homebrew release: PRs not supported yet"); + logger.warn('Skipping homebrew release: PRs not supported yet'); return undefined; } const params = { - content: Buffer.from(data).toString("base64"), + content: Buffer.from(data).toString('base64'), message: `release: ${formulaName} ${version}`, owner: tapRepo.owner, path: formulaPath, repo: tapRepo.repo, - sha: (await this.getFormulaSha(formulaPath)) || "", + sha: (await this.getFormulaSha(formulaPath)) || '', }; logger.info( @@ -204,7 +204,7 @@ export class BrewTarget extends BaseTarget { `formula ${formulaName}` ); - const action = params.sha ? "Updating" : "Creating"; + const action = params.sha ? 'Updating' : 'Creating'; logger.debug( `${action} file ${params.owner}/${params.repo}:${params.path} (${params.sha})` ); @@ -214,6 +214,6 @@ export class BrewTarget extends BaseTarget { } else { logger.info(`[dry-run] Skipping file action: ${action}`); } - logger.info("Homebrew release complete"); + logger.info('Homebrew release complete'); } } diff --git a/src/targets/cocoapods.ts b/src/targets/cocoapods.ts index de6e1985..cdd3cbc7 100644 --- a/src/targets/cocoapods.ts +++ b/src/targets/cocoapods.ts @@ -1,22 +1,22 @@ -import * as Github from "@octokit/rest"; -import * as fs from "fs"; -import { basename, join } from "path"; -import { promisify } from "util"; - -import { getGlobalGithubConfig } from "../config"; -import { logger as loggerRaw } from "../logger"; -import { GithubGlobalConfig, TargetConfig } from "../schemas/project_config"; -import { ConfigurationError, reportError } from "../utils/errors"; -import { withTempDir } from "../utils/files"; -import { getFile, getGithubClient } from "../utils/githubApi"; -import { checkExecutableIsPresent, spawnProcess } from "../utils/system"; -import { BaseTarget } from "./base"; -import { BaseArtifactProvider } from "../artifact_providers/base"; +import * as Github from '@octokit/rest'; +import * as fs from 'fs'; +import { basename, join } from 'path'; +import { promisify } from 'util'; + +import { getGlobalGithubConfig } from '../config'; +import { logger as loggerRaw } from '../logger'; +import { GithubGlobalConfig, TargetConfig } from '../schemas/project_config'; +import { ConfigurationError, reportError } from '../utils/errors'; +import { withTempDir } from '../utils/files'; +import { getFile, getGithubClient } from '../utils/githubApi'; +import { checkExecutableIsPresent, spawnProcess } from '../utils/system'; +import { BaseTarget } from './base'; +import { BaseArtifactProvider } from '../artifact_providers/base'; const writeFile = promisify(fs.writeFile); -const logger = loggerRaw.withScope("[cocoapods]"); +const logger = loggerRaw.withScope('[cocoapods]'); -const DEFAULT_COCOAPODS_BIN = "pod"; +const DEFAULT_COCOAPODS_BIN = 'pod'; /** * Command to launch cocoapods @@ -34,7 +34,7 @@ export interface CocoapodsTargetOptions { */ export class CocoapodsTarget extends BaseTarget { /** Target name */ - public readonly name: string = "cocoapods"; + public readonly name: string = 'cocoapods'; /** Target options */ public readonly cocoapodsConfig: CocoapodsTargetOptions; /** Github client */ @@ -59,7 +59,7 @@ export class CocoapodsTarget extends BaseTarget { public getCocoapodsConfig(): CocoapodsTargetOptions { const specPath = this.config.specPath; if (!specPath) { - throw new ConfigurationError("No podspec path provided!"); + throw new ConfigurationError('No podspec path provided!'); } return { @@ -96,13 +96,13 @@ export class CocoapodsTarget extends BaseTarget { await withTempDir( async (directory) => { const filePath = join(directory, fileName); - await writeFile(filePath, specContents, "utf8"); + await writeFile(filePath, specContents, 'utf8'); logger.info(`Pushing podspec "${fileName}" to cocoapods...`); - await spawnProcess(COCOAPODS_BIN, ["setup"]); + await spawnProcess(COCOAPODS_BIN, ['setup']); await spawnProcess( COCOAPODS_BIN, - ["trunk", "push", fileName, "--allow-warnings"], + ['trunk', 'push', fileName, '--allow-warnings'], { cwd: directory, env: { @@ -112,9 +112,9 @@ export class CocoapodsTarget extends BaseTarget { ); }, true, - "craft-cocoapods-" + 'craft-cocoapods-' ); - logger.info("Cocoapods release complete"); + logger.info('Cocoapods release complete'); } } diff --git a/src/targets/crates.ts b/src/targets/crates.ts index 05bb28db..2a63d708 100644 --- a/src/targets/crates.ts +++ b/src/targets/crates.ts @@ -1,26 +1,26 @@ -import * as fs from "fs"; -import * as path from "path"; - -import * as _ from "lodash"; -import simpleGit from "simple-git"; - -import { getGlobalGithubConfig } from "../config"; -import { logger as loggerRaw } from "../logger"; -import { GithubGlobalConfig, TargetConfig } from "../schemas/project_config"; -import { forEachChained } from "../utils/async"; -import { ConfigurationError } from "../utils/errors"; -import { withTempDir } from "../utils/files"; +import * as fs from 'fs'; +import * as path from 'path'; + +import * as _ from 'lodash'; +import simpleGit from 'simple-git'; + +import { getGlobalGithubConfig } from '../config'; +import { logger as loggerRaw } from '../logger'; +import { GithubGlobalConfig, TargetConfig } from '../schemas/project_config'; +import { forEachChained } from '../utils/async'; +import { ConfigurationError } from '../utils/errors'; +import { withTempDir } from '../utils/files'; import { checkExecutableIsPresent, sleepAsync, spawnProcess, -} from "../utils/system"; -import { BaseTarget } from "./base"; -import { BaseArtifactProvider } from "../artifact_providers/base"; +} from '../utils/system'; +import { BaseTarget } from './base'; +import { BaseArtifactProvider } from '../artifact_providers/base'; -const logger = loggerRaw.withScope("[crates]"); +const logger = loggerRaw.withScope('[crates]'); -const DEFAULT_CARGO_BIN = "cargo"; +const DEFAULT_CARGO_BIN = 'cargo'; /** * Command to launch cargo @@ -32,7 +32,7 @@ const CARGO_BIN = process.env.CARGO_BIN || DEFAULT_CARGO_BIN; * dependency. This sometimes indicates a false positive if the cache has not * been updated. */ -const VERSION_ERROR = "failed to select a version for the requirement"; +const VERSION_ERROR = 'failed to select a version for the requirement'; /** * Maximum number of attempts including the initial one when publishing fails @@ -103,7 +103,7 @@ export interface CrateMetadata { */ export class CratesTarget extends BaseTarget { /** Target name */ - public readonly name: string = "crates"; + public readonly name: string = 'crates'; /** Target options */ public readonly cratesConfig: CratesTargetOptions; @@ -145,11 +145,11 @@ export class CratesTarget extends BaseTarget { */ public async getCrateMetadata(directory: string): Promise { const args = [ - "metadata", - "--manifest-path", + 'metadata', + '--manifest-path', `${directory}/Cargo.toml`, - "--no-deps", - "--format-version=1", + '--no-deps', + '--format-version=1', ]; logger.info(`Loading workspace information from ${directory}/Cargo.toml`); @@ -160,7 +160,7 @@ export class CratesTarget extends BaseTarget { { enableInDryRunMode: true } ); if (!metadata) { - throw new ConfigurationError("Empty Cargo metadata!"); + throw new ConfigurationError('Empty Cargo metadata!'); } return JSON.parse(metadata.toString()); } @@ -185,7 +185,7 @@ export class CratesTarget extends BaseTarget { const isWorkspaceDependency = (dep: CrateDependency) => { // Optionally exclude dev dependencies from dependency resolution. When // this flag is provided, these usually lead to circular dependencies. - if (this.cratesConfig.noDevDeps && dep.kind === "dev") { + if (this.cratesConfig.noDevDeps && dep.kind === 'dev') { return false; } @@ -202,7 +202,7 @@ export class CratesTarget extends BaseTarget { ); if (leafDependencies.length === 0) { - throw new Error("Circular dependency detected!"); + throw new Error('Circular dependency detected!'); } leafDependencies.forEach((next) => { @@ -235,7 +235,7 @@ export class CratesTarget extends BaseTarget { logger.debug( `Publishing packages in the following order: ${crates .map((c) => c.name) - .join(", ")}` + .join(', ')}` ); return forEachChained(crates, async (crate) => this.publishPackage(crate)); } @@ -248,12 +248,12 @@ export class CratesTarget extends BaseTarget { */ public async publishPackage(crate: CratePackage): Promise { const args = this.cratesConfig.noDevDeps - ? ["hack", "publish", "--allow-dirty", "--no-dev-deps"] - : ["publish"]; + ? ['hack', 'publish', '--allow-dirty', '--no-dev-deps'] + : ['publish']; args.push( - "--no-verify", // Verification should be done on the CI stage - "--manifest-path", + '--no-verify', // Verification should be done on the CI stage + '--manifest-path', crate.manifest_path ); @@ -300,12 +300,12 @@ export class CratesTarget extends BaseTarget { await git.checkout(revision); logger.info(`Checking out submodules`); - await git.submoduleUpdate(["--init"]); + await git.submoduleUpdate(['--init']); // Cargo seems to run into problems if the crate resides within a git // checkout located in a memory file system on Mac (e.g. /tmp). This can be // avoided by signaling to cargo that this is not a git checkout. - const gitdir = path.join(directory, ".git"); + const gitdir = path.join(directory, '.git'); fs.renameSync(gitdir, `${gitdir}.bak`); } @@ -326,9 +326,9 @@ export class CratesTarget extends BaseTarget { await this.publishWorkspace(directory); }, true, - "craft-crates-" + 'craft-crates-' ); - logger.info("Crates release complete"); + logger.info('Crates release complete'); } } diff --git a/src/targets/docker.ts b/src/targets/docker.ts index 9f671665..4aee6535 100644 --- a/src/targets/docker.ts +++ b/src/targets/docker.ts @@ -1,14 +1,14 @@ -import { logger as loggerRaw } from "../logger"; -import { TargetConfig } from "../schemas/project_config"; -import { BaseArtifactProvider } from "../artifact_providers/base"; -import { ConfigurationError } from "../utils/errors"; -import { renderTemplateSafe } from "../utils/strings"; -import { checkExecutableIsPresent, spawnProcess } from "../utils/system"; -import { BaseTarget } from "./base"; +import { logger as loggerRaw } from '../logger'; +import { TargetConfig } from '../schemas/project_config'; +import { BaseArtifactProvider } from '../artifact_providers/base'; +import { ConfigurationError } from '../utils/errors'; +import { renderTemplateSafe } from '../utils/strings'; +import { checkExecutableIsPresent, spawnProcess } from '../utils/system'; +import { BaseTarget } from './base'; -const logger = loggerRaw.withScope("[docker]"); +const logger = loggerRaw.withScope('[docker]'); -const DEFAULT_DOCKER_BIN = "docker"; +const DEFAULT_DOCKER_BIN = 'docker'; /** * Command to launch docker @@ -34,7 +34,7 @@ export interface DockerTargetOptions { */ export class DockerTarget extends BaseTarget { /** Target name */ - public readonly name: string = "docker"; + public readonly name: string = 'docker'; /** Target options */ public readonly dockerConfig: DockerTargetOptions; @@ -56,7 +56,7 @@ export class DockerTarget extends BaseTarget { `Cannot perform Docker release: missing credentials. Please use DOCKER_USERNAME and DOCKER_PASSWORD environment variables.`.replace( /^\s+/gm, - "" + '' ) ); } @@ -65,8 +65,8 @@ export class DockerTarget extends BaseTarget { password: process.env.DOCKER_PASSWORD, source: this.config.source, target: this.config.target, - sourceTemplate: this.config.sourceFormat || "{{{source}}}:{{{revision}}}", - targetTemplate: this.config.targetFormat || "{{{target}}}:{{{version}}}", + sourceTemplate: this.config.sourceFormat || '{{{source}}}:{{{revision}}}', + targetTemplate: this.config.targetFormat || '{{{target}}}:{{{version}}}', username: process.env.DOCKER_USERNAME, }; } @@ -79,7 +79,7 @@ export class DockerTarget extends BaseTarget { public async login(): Promise { const { username, password } = this.dockerConfig; return spawnProcess(DOCKER_BIN, [ - "login", + 'login', `--username=${username}`, `--password=${password}`, ]); @@ -90,14 +90,14 @@ export class DockerTarget extends BaseTarget { * @param revision Image tag, usually the git revision */ public async pull(revision: string): Promise { - logger.debug("Pulling source image..."); + logger.debug('Pulling source image...'); const sourceImage = renderTemplateSafe(this.dockerConfig.sourceTemplate, { ...this.dockerConfig, revision, }); return spawnProcess( DOCKER_BIN, - ["pull", sourceImage], + ['pull', sourceImage], {}, { enableInDryRunMode: true } ); @@ -117,11 +117,11 @@ export class DockerTarget extends BaseTarget { ...this.dockerConfig, version, }); - logger.debug("Tagging target image..."); - await spawnProcess(DOCKER_BIN, ["tag", sourceImage, targetImage]); + logger.debug('Tagging target image...'); + await spawnProcess(DOCKER_BIN, ['tag', sourceImage, targetImage]); return spawnProcess( DOCKER_BIN, - ["push", targetImage], + ['push', targetImage], {}, { showStdout: true } ); @@ -138,6 +138,6 @@ export class DockerTarget extends BaseTarget { await this.pull(revision); await this.push(revision, version); - logger.info("Docker release complete"); + logger.info('Docker release complete'); } } diff --git a/src/targets/gcs.ts b/src/targets/gcs.ts index ded86b88..92d44e9e 100644 --- a/src/targets/gcs.ts +++ b/src/targets/gcs.ts @@ -1,20 +1,20 @@ -import { logger as loggerRaw } from "../logger"; -import { TargetConfig } from "../schemas/project_config"; -import { forEachChained } from "../utils/async"; -import { ConfigurationError, reportError } from "../utils/errors"; +import { logger as loggerRaw } from '../logger'; +import { TargetConfig } from '../schemas/project_config'; +import { forEachChained } from '../utils/async'; +import { ConfigurationError, reportError } from '../utils/errors'; import { BucketPath, CraftGCSClient, GCSBucketConfig, getGCSCredsFromEnv, DEFAULT_UPLOAD_METADATA, -} from "../utils/gcsApi"; -import { renderTemplateSafe } from "../utils/strings"; -import { BaseTarget } from "./base"; +} from '../utils/gcsApi'; +import { renderTemplateSafe } from '../utils/strings'; +import { BaseTarget } from './base'; import { BaseArtifactProvider, RemoteArtifact, -} from "../artifact_providers/base"; +} from '../artifact_providers/base'; const logger = loggerRaw.withScope(`[gcs]`); @@ -23,7 +23,7 @@ const logger = loggerRaw.withScope(`[gcs]`); * * Omits required property `path` since that will be computed dynamically later. */ -interface PathTemplate extends Omit { +interface PathTemplate extends Omit { /** * Template for the path, into which `version` and `revision` can be * substituted @@ -44,7 +44,7 @@ export interface GCSTargetConfig extends GCSBucketConfig { */ export class GcsTarget extends BaseTarget { /** Target name */ - public readonly name: string = "gcs"; + public readonly name: string = 'gcs'; /** Target options */ public readonly targetConfig: GCSTargetConfig; /** GCS API client */ @@ -65,12 +65,12 @@ export class GcsTarget extends BaseTarget { protected getGCSTargetConfig(): GCSTargetConfig { const { project_id, client_email, private_key } = getGCSCredsFromEnv( { - name: "CRAFT_GCS_TARGET_CREDS_JSON", - legacyName: "CRAFT_GCS_CREDENTIALS_JSON", + name: 'CRAFT_GCS_TARGET_CREDS_JSON', + legacyName: 'CRAFT_GCS_CREDENTIALS_JSON', }, { - name: "CRAFT_GCS_TARGET_CREDS_PATH", - legacyName: "CRAFT_GCS_CREDENTIALS_PATH", + name: 'CRAFT_GCS_TARGET_CREDS_PATH', + legacyName: 'CRAFT_GCS_CREDENTIALS_PATH', }, logger ); @@ -78,7 +78,7 @@ export class GcsTarget extends BaseTarget { const bucketName = this.config.bucket; // TODO (kmclb) get rid of this check once config validation is working if (!bucketName) { - reportError("No GCS bucket provided!"); + reportError('No GCS bucket provided!'); } const pathTemplates: PathTemplate[] = this.parseRawPathConfig( @@ -111,12 +111,12 @@ export class GcsTarget extends BaseTarget { // in JS empty arrays are truthy (rawPathConfig.length && rawPathConfig.length === 0) ) { - reportError("No bucket paths provided!"); + reportError('No bucket paths provided!'); } // if there's only one path, and no metadata specified, path config can be // provided as a string rather than an array of objects - else if (typeof rawPathConfig === "string") { + else if (typeof rawPathConfig === 'string') { parsedTemplates = [ { template: rawPathConfig, @@ -129,7 +129,7 @@ export class GcsTarget extends BaseTarget { // and `metadata` else if (Array.isArray(rawPathConfig)) { rawPathConfig.forEach((configEntry: any) => { - if (typeof configEntry !== "object") { + if (typeof configEntry !== 'object') { reportError( `Invalid bucket destination: ${JSON.stringify( configEntry @@ -142,7 +142,7 @@ export class GcsTarget extends BaseTarget { if (!template) { reportError(`Invalid bucket path template: ${template}`); } - if (metadata && typeof metadata !== "object") { + if (metadata && typeof metadata !== 'object') { reportError( `Invalid metadata for path "${template}": "${JSON.stringify( metadata @@ -191,7 +191,7 @@ export class GcsTarget extends BaseTarget { }); // enforce the constraint that all paths must start with a slash - if (realPath[0] !== "/") { + if (realPath[0] !== '/') { realPath = `/${realPath}`; } logger.debug( @@ -213,7 +213,7 @@ export class GcsTarget extends BaseTarget { const artifacts = await this.getArtifactsForRevision(revision); if (!artifacts.length) { throw new ConfigurationError( - "No artifacts to publish: please check your configuration!" + 'No artifacts to publish: please check your configuration!' ); } @@ -258,6 +258,6 @@ export class GcsTarget extends BaseTarget { } ); - logger.info("Upload to GCS complete."); + logger.info('Upload to GCS complete.'); } } diff --git a/src/targets/gem.ts b/src/targets/gem.ts index 2bb37507..7ed6bcb9 100644 --- a/src/targets/gem.ts +++ b/src/targets/gem.ts @@ -1,16 +1,16 @@ -import { logger as loggerRaw } from "../logger"; +import { logger as loggerRaw } from '../logger'; import { BaseArtifactProvider, RemoteArtifact, -} from "../artifact_providers/base"; -import { reportError } from "../utils/errors"; -import { checkExecutableIsPresent, spawnProcess } from "../utils/system"; -import { BaseTarget } from "./base"; -import { TargetConfig } from "src/schemas/project_config"; +} from '../artifact_providers/base'; +import { reportError } from '../utils/errors'; +import { checkExecutableIsPresent, spawnProcess } from '../utils/system'; +import { BaseTarget } from './base'; +import { TargetConfig } from 'src/schemas/project_config'; -const logger = loggerRaw.withScope("[gem]"); +const logger = loggerRaw.withScope('[gem]'); -const DEFAULT_GEM_BIN = "gem"; +const DEFAULT_GEM_BIN = 'gem'; /** * Command to launch gem @@ -27,7 +27,7 @@ const DEFAULT_GEM_REGEX = /^.*(\.gem)$/; */ export class GemTarget extends BaseTarget { /** Target name */ - public readonly name: string = "gem"; + public readonly name: string = 'gem'; public constructor( config: TargetConfig, @@ -44,7 +44,7 @@ export class GemTarget extends BaseTarget { * @returns A promise that resolves when the gem pushed */ public async pushGem(path: string): Promise { - return spawnProcess(GEM_BIN, ["push", path]); + return spawnProcess(GEM_BIN, ['push', path]); } /** @@ -54,13 +54,13 @@ export class GemTarget extends BaseTarget { * @param revision Git commit SHA to be published */ public async publish(_version: string, revision: string): Promise { - logger.debug("Fetching artifact list..."); + logger.debug('Fetching artifact list...'); const packageFiles = await this.getArtifactsForRevision(revision, { includeNames: DEFAULT_GEM_REGEX, }); if (!packageFiles.length) { - reportError("Cannot push gem: no packages found"); + reportError('Cannot push gem: no packages found'); return undefined; } @@ -72,6 +72,6 @@ export class GemTarget extends BaseTarget { }) ); - logger.info("Successfully registered gem"); + logger.info('Successfully registered gem'); } } diff --git a/src/targets/ghPages.ts b/src/targets/ghPages.ts index c36525c6..99e88b50 100644 --- a/src/targets/ghPages.ts +++ b/src/targets/ghPages.ts @@ -1,33 +1,33 @@ -import * as fs from "fs"; -import * as path from "path"; +import * as fs from 'fs'; +import * as path from 'path'; -import * as Github from "@octokit/rest"; -import simpleGit from "simple-git"; +import * as Github from '@octokit/rest'; +import simpleGit from 'simple-git'; -import { getGlobalGithubConfig } from "../config"; -import { logger as loggerRaw } from "../logger"; -import { GithubGlobalConfig, TargetConfig } from "../schemas/project_config"; -import { ConfigurationError, reportError } from "../utils/errors"; -import { withTempDir } from "../utils/files"; +import { getGlobalGithubConfig } from '../config'; +import { logger as loggerRaw } from '../logger'; +import { GithubGlobalConfig, TargetConfig } from '../schemas/project_config'; +import { ConfigurationError, reportError } from '../utils/errors'; +import { withTempDir } from '../utils/files'; import { getAuthUsername, getGithubApiToken, getGithubClient, GithubRemote, -} from "../utils/githubApi"; -import { isDryRun } from "../utils/helpers"; -import { extractZipArchive } from "../utils/system"; -import { BaseTarget } from "./base"; -import { BaseArtifactProvider } from "../artifact_providers/base"; +} from '../utils/githubApi'; +import { isDryRun } from '../utils/helpers'; +import { extractZipArchive } from '../utils/system'; +import { BaseTarget } from './base'; +import { BaseArtifactProvider } from '../artifact_providers/base'; -const logger = loggerRaw.withScope("[gh-pages]"); +const logger = loggerRaw.withScope('[gh-pages]'); /** * Regex for docs archives */ const DEFAULT_DEPLOY_ARCHIVE_REGEX = /^(?:.+-)?gh-pages\.zip$/; -const DEFAULT_DEPLOY_BRANCH = "gh-pages"; +const DEFAULT_DEPLOY_BRANCH = 'gh-pages'; /** Target options for "gh-pages" */ export interface GhPagesConfig { @@ -44,7 +44,7 @@ export interface GhPagesConfig { */ export class GhPagesTarget extends BaseTarget { /** Target name */ - public readonly name: string = "gh-pages"; + public readonly name: string = 'gh-pages'; /** Target options */ public readonly ghPagesConfig: GhPagesConfig; /** Github client */ @@ -76,7 +76,7 @@ export class GhPagesTarget extends BaseTarget { githubRepo = this.githubRepo.repo; } else { throw new ConfigurationError( - "[gh-pages] Invalid repository configuration: check repo owner and name" + '[gh-pages] Invalid repository configuration: check repo owner and name' ); } @@ -105,10 +105,10 @@ export class GhPagesTarget extends BaseTarget { directory: string ): Promise { // Check that the directory is empty - const dirContents = fs.readdirSync(directory).filter((f) => f !== ".git"); + const dirContents = fs.readdirSync(directory).filter((f) => f !== '.git'); if (dirContents.length > 0) { throw new Error( - "Destination directory is not empty: cannot extract the acrhive!" + 'Destination directory is not empty: cannot extract the acrhive!' ); } @@ -119,12 +119,12 @@ export class GhPagesTarget extends BaseTarget { // If there's a single top-level directory -- move its contents to the git root const newDirContents = fs .readdirSync(directory) - .filter((f) => f !== ".git"); + .filter((f) => f !== '.git'); if ( newDirContents.length === 1 && fs.statSync(path.join(directory, newDirContents[0])).isDirectory() ) { - logger.debug("Single top-level directory found, moving files from it..."); + logger.debug('Single top-level directory found, moving files from it...'); const innerDirPath = path.join(directory, newDirContents[0]); fs.readdirSync(innerDirPath).forEach((item) => { const srcPath = path.join(innerDirPath, item); @@ -164,12 +164,12 @@ export class GhPagesTarget extends BaseTarget { logger.debug( `Branch ${branch} does not exist, creating a new orphaned branch...` ); - await git.checkout(["--orphan", branch]); + await git.checkout(['--orphan', branch]); } // Additional check, just in case const repoStatus = await git.status(); - if (repoStatus.current !== "No" && repoStatus.current !== branch) { + if (repoStatus.current !== 'No' && repoStatus.current !== branch) { throw new Error( `Something went very wrong: cannot switch to branch "${branch}"` ); @@ -177,21 +177,21 @@ export class GhPagesTarget extends BaseTarget { // Clean the previous state logger.debug(`Removing existing files from the working tree...`); - await git.rm(["-r", "-f", "."]); + await git.rm(['-r', '-f', '.']); // Extract the archive await this.extractAssets(archivePath, directory); // Commit - await git.add(["."]); + await git.add(['.']); await git.commit(`craft(gh-pages): update, version "${version}"`); // Push! logger.info(`Pushing branch "${branch}"...`); if (!isDryRun()) { - await git.push("origin", branch, ["--set-upstream"]); + await git.push('origin', branch, ['--set-upstream']); } else { - logger.info("[dry-run] Not pushing the branch."); + logger.info('[dry-run] Not pushing the branch.'); } } @@ -201,12 +201,12 @@ export class GhPagesTarget extends BaseTarget { public async publish(version: string, revision: string): Promise { const { githubOwner, githubRepo, branch } = this.ghPagesConfig; - logger.debug("Fetching artifact list..."); + logger.debug('Fetching artifact list...'); const packageFiles = await this.getArtifactsForRevision(revision, { includeNames: DEFAULT_DEPLOY_ARCHIVE_REGEX, }); if (!packageFiles.length) { - reportError("Cannot release to GH-pages: no artifacts found"); + reportError('Cannot release to GH-pages: no artifacts found'); return undefined; } else if (packageFiles.length > 1) { reportError( @@ -239,9 +239,9 @@ export class GhPagesTarget extends BaseTarget { version ), true, - "craft-gh-pages-" + 'craft-gh-pages-' ); - logger.info("GitHub pages release complete"); + logger.info('GitHub pages release complete'); } } diff --git a/src/targets/github.ts b/src/targets/github.ts index fdd9d29e..f0160a68 100644 --- a/src/targets/github.ts +++ b/src/targets/github.ts @@ -1,29 +1,29 @@ -import * as Github from "@octokit/rest"; -import { createReadStream, statSync } from "fs"; -import { basename } from "path"; +import * as Github from '@octokit/rest'; +import { createReadStream, statSync } from 'fs'; +import { basename } from 'path'; -import { getConfiguration, getGlobalGithubConfig } from "../config"; -import { logger as loggerRaw } from "../logger"; -import { GithubGlobalConfig, TargetConfig } from "../schemas/project_config"; -import { DEFAULT_CHANGELOG_PATH, findChangeset } from "../utils/changes"; +import { getConfiguration, getGlobalGithubConfig } from '../config'; +import { logger as loggerRaw } from '../logger'; +import { GithubGlobalConfig, TargetConfig } from '../schemas/project_config'; +import { DEFAULT_CHANGELOG_PATH, findChangeset } from '../utils/changes'; import { getFile, getGithubClient, HTTP_RESPONSE_5XX, HTTP_UNPROCESSABLE_ENTITY, retryHttp, -} from "../utils/githubApi"; -import { isDryRun } from "../utils/helpers"; -import { isPreviewRelease, versionToTag } from "../utils/version"; -import { BaseTarget } from "./base"; -import { BaseArtifactProvider } from "../artifact_providers/base"; +} from '../utils/githubApi'; +import { isDryRun } from '../utils/helpers'; +import { isPreviewRelease, versionToTag } from '../utils/version'; +import { BaseTarget } from './base'; +import { BaseArtifactProvider } from '../artifact_providers/base'; -const logger = loggerRaw.withScope("[github]"); +const logger = loggerRaw.withScope('[github]'); /** * Default content type for GitHub release assets */ -export const DEFAULT_CONTENT_TYPE = "application/octet-stream"; +export const DEFAULT_CONTENT_TYPE = 'application/octet-stream'; /** * Configuration options for the Github target @@ -55,14 +55,14 @@ interface GithubRelease { /** * Tag type as used in GitdataCreateTagParams from Github API */ -type GithubCreateTagType = "commit" | "tree" | "blob"; +type GithubCreateTagType = 'commit' | 'tree' | 'blob'; /** * Target responsible for publishing releases on Github */ export class GithubTarget extends BaseTarget { /** Target name */ - public readonly name: string = "github"; + public readonly name: string = 'github'; /** Target options */ public readonly githubConfig: GithubTargetConfig; /** Github client */ @@ -77,11 +77,11 @@ export class GithubTarget extends BaseTarget { ...getGlobalGithubConfig(), annotatedTag: this.config.annotatedTag === undefined || !!this.config.annotatedTag, - changelog: getConfiguration().changelog || "", + changelog: getConfiguration().changelog || '', previewReleases: this.config.previewReleases === undefined || !!this.config.previewReleases, - tagPrefix: this.config.tagPrefix || "", + tagPrefix: this.config.tagPrefix || '', }; this.github = getGithubClient(); } @@ -110,7 +110,7 @@ export class GithubTarget extends BaseTarget { owner: this.githubConfig.owner, repo: this.githubConfig.repo, tag, - type: "commit" as GithubCreateTagType, + type: 'commit' as GithubCreateTagType, }; const tagCreatedResponse = await this.github.git.createTag(createTagParams); @@ -178,7 +178,7 @@ export class GithubTarget extends BaseTarget { revision ); const changes = (changelog && findChangeset(changelog, tag)) || {}; - logger.debug("Changes extracted from changelog: ", JSON.stringify(changes)); + logger.debug('Changes extracted from changelog: ', JSON.stringify(changes)); const createReleaseParams = { draft: false, @@ -196,12 +196,12 @@ export class GithubTarget extends BaseTarget { if (this.githubConfig.annotatedTag) { await this.createAnnotatedTag(version, revision, tag); // We've just created the tag, so "target_commitish" will not be used. - createReleaseParams.target_commitish = ""; + createReleaseParams.target_commitish = ''; } logger.info( `Creating a new ${ - isPreview ? "*preview* " : "" + isPreview ? '*preview* ' : '' }release for tag "${tag}"` ); const created = await this.github.repos.createRelease( @@ -213,7 +213,7 @@ export class GithubTarget extends BaseTarget { return { id: 0, tag_name: tag, - upload_url: "", + upload_url: '', }; } } @@ -312,18 +312,18 @@ export class GithubTarget extends BaseTarget { const stats = statSync(path); const name = basename(path); const params = { - "Content-Length": stats.size, - "Content-Type": contentTypeProcessed, + 'Content-Length': stats.size, + 'Content-Type': contentTypeProcessed, file: createReadStream(path), headers: { - "content-length": stats.size, - "content-type": contentTypeProcessed, + 'content-length': stats.size, + 'content-type': contentTypeProcessed, }, id: release.id, name, url: release.upload_url, }; - logger.debug("Upload parameters:", JSON.stringify(params)); + logger.debug('Upload parameters:', JSON.stringify(params)); logger.info( `Uploading asset "${name}" to ${this.githubConfig.owner}/${this.githubConfig.repo}:${release.tag_name}` ); @@ -333,7 +333,7 @@ export class GithubTarget extends BaseTarget { async () => this.github.repos.uploadReleaseAsset(params), { cleanupFn: async () => { - logger.debug("Cleaning up before the next retry..."); + logger.debug('Cleaning up before the next retry...'); return this.deleteAssetsByFilename(release, name); }, retries: 5, @@ -370,7 +370,7 @@ export class GithubTarget extends BaseTarget { } else { const assets = await this.getAssetsForRelease(release); if (assets.length > 0) { - logger.warn("Existing assets found for the release, deleting them..."); + logger.warn('Existing assets found for the release, deleting them...'); await this.deleteAssets(assets); logger.debug(`Deleted ${assets.length} assets`); } diff --git a/src/targets/index.ts b/src/targets/index.ts index 769caac0..8fb44f85 100644 --- a/src/targets/index.ts +++ b/src/targets/index.ts @@ -1,18 +1,18 @@ -import { TargetConfig } from "src/schemas/project_config"; -import { BaseTarget } from "./base"; -import { BrewTarget } from "./brew"; -import { CocoapodsTarget } from "./cocoapods"; -import { CratesTarget } from "./crates"; -import { DockerTarget } from "./docker"; -import { GcsTarget } from "./gcs"; -import { GemTarget } from "./gem"; -import { GhPagesTarget } from "./ghPages"; -import { GithubTarget } from "./github"; -import { NpmTarget } from "./npm"; -import { NugetTarget } from "./nuget"; -import { PypiTarget } from "./pypi"; -import { RegistryTarget } from "./registry"; -import { AwsLambdaLayerTarget } from "./awsLambdaLayer"; +import { TargetConfig } from 'src/schemas/project_config'; +import { BaseTarget } from './base'; +import { BrewTarget } from './brew'; +import { CocoapodsTarget } from './cocoapods'; +import { CratesTarget } from './crates'; +import { DockerTarget } from './docker'; +import { GcsTarget } from './gcs'; +import { GemTarget } from './gem'; +import { GhPagesTarget } from './ghPages'; +import { GithubTarget } from './github'; +import { NpmTarget } from './npm'; +import { NugetTarget } from './nuget'; +import { PypiTarget } from './pypi'; +import { RegistryTarget } from './registry'; +import { AwsLambdaLayerTarget } from './awsLambdaLayer'; export const TARGET_MAP: { [key: string]: typeof BaseTarget } = { brew: BrewTarget, @@ -21,21 +21,21 @@ export const TARGET_MAP: { [key: string]: typeof BaseTarget } = { docker: DockerTarget, gcs: GcsTarget, gem: GemTarget, - "gh-pages": GhPagesTarget, + 'gh-pages': GhPagesTarget, github: GithubTarget, npm: NpmTarget, nuget: NugetTarget, pypi: PypiTarget, registry: RegistryTarget, - "aws-lambda-layer": AwsLambdaLayerTarget, + 'aws-lambda-layer': AwsLambdaLayerTarget, }; /** Targets that are treated specially */ export enum SpecialTarget { /** This targets does not do any publishing, only related workflow actions (e.g. merging the release branch) */ - None = "none", + None = 'none', /** This target is an alias for running all configured targets */ - All = "all", + All = 'all', } /** @@ -62,5 +62,5 @@ export function getTargetByName( export function getTargetId(target: TargetConfig): string { return target.id ? `${target.name}[${target.id}]` - : target.name || "__undefined__"; + : target.name || '__undefined__'; } diff --git a/src/targets/npm.ts b/src/targets/npm.ts index 0f1437e7..d57cee46 100644 --- a/src/targets/npm.ts +++ b/src/targets/npm.ts @@ -1,32 +1,32 @@ -import { SpawnOptions, spawnSync } from "child_process"; -import * as inquirer from "inquirer"; - -import { logger as loggerRaw } from "../logger"; -import { TargetConfig } from "../schemas/project_config"; -import { ConfigurationError, reportError } from "../utils/errors"; -import { isDryRun } from "../utils/helpers"; -import { hasExecutable, spawnProcess } from "../utils/system"; -import { isPreviewRelease, parseVersion } from "../utils/version"; -import { BaseTarget } from "./base"; +import { SpawnOptions, spawnSync } from 'child_process'; +import * as inquirer from 'inquirer'; + +import { logger as loggerRaw } from '../logger'; +import { TargetConfig } from '../schemas/project_config'; +import { ConfigurationError, reportError } from '../utils/errors'; +import { isDryRun } from '../utils/helpers'; +import { hasExecutable, spawnProcess } from '../utils/system'; +import { isPreviewRelease, parseVersion } from '../utils/version'; +import { BaseTarget } from './base'; import { BaseArtifactProvider, RemoteArtifact, -} from "../artifact_providers/base"; -import { withTempFile } from "../utils/files"; -import { writeFileSync } from "fs"; +} from '../artifact_providers/base'; +import { withTempFile } from '../utils/files'; +import { writeFileSync } from 'fs'; -const logger = loggerRaw.withScope("[npm]"); +const logger = loggerRaw.withScope('[npm]'); /** Command to launch "npm" */ -export const NPM_BIN = process.env.NPM_BIN || "npm"; +export const NPM_BIN = process.env.NPM_BIN || 'npm'; /** Command to launch "yarn" */ -export const YARN_BIN = process.env.YARN_BIN || "yarn"; +export const YARN_BIN = process.env.YARN_BIN || 'yarn'; const NPM_MIN_MAJOR = 5; const NPM_MIN_MINOR = 6; -const NPM_TOKEN_ENV_VAR = "NPM_TOKEN"; +const NPM_TOKEN_ENV_VAR = 'NPM_TOKEN'; /** A regular expression used to find the package tarball */ const DEFAULT_PACKAGE_REGEX = /^.*\d\.\d.*\.tgz$/; @@ -34,9 +34,9 @@ const DEFAULT_PACKAGE_REGEX = /^.*\d\.\d.*\.tgz$/; /** Access specifiers for NPM packages. See npm-publish doc for more info */ export enum NpmPackageAccess { /** Public access: anyone can see the package */ - PUBLIC = "public", + PUBLIC = 'public', /** Restricted access: scoped packages are restricted by default, for example */ - RESTRICTED = "restricted", + RESTRICTED = 'restricted', } /** NPM target configuration options */ @@ -64,7 +64,7 @@ interface NpmPublishOptions { */ export class NpmTarget extends BaseTarget { /** Target name */ - public readonly name: string = "npm"; + public readonly name: string = 'npm'; /** Target options */ public readonly npmConfig: NpmTargetOptions; @@ -82,8 +82,8 @@ export class NpmTarget extends BaseTarget { */ protected checkRequirements(): void { if (hasExecutable(NPM_BIN)) { - logger.debug("Checking that NPM has recent version..."); - const npmVersion = spawnSync(NPM_BIN, ["--version"]) + logger.debug('Checking that NPM has recent version...'); + const npmVersion = spawnSync(NPM_BIN, ['--version']) .stdout.toString() .trim(); const parsedVersion = parseVersion(npmVersion); @@ -101,7 +101,7 @@ export class NpmTarget extends BaseTarget { } logger.debug(`Found NPM version ${npmVersion}`); } else if (hasExecutable(YARN_BIN)) { - const yarnVersion = spawnSync(YARN_BIN, ["--version"]) + const yarnVersion = spawnSync(YARN_BIN, ['--version']) .stdout.toString() .trim(); logger.debug(`Found Yarn version ${yarnVersion}`); @@ -116,11 +116,11 @@ export class NpmTarget extends BaseTarget { protected async requestOtp(): Promise { const questions = [ { - message: "Looks like your NPM account uses 2FA. Enter OTP:", - name: "otp", - type: "input", + message: 'Looks like your NPM account uses 2FA. Enter OTP:', + name: 'otp', + type: 'input', validate: (input: string) => - (input.length > 3 && input.length < 10) || "Valid OTP, please", + (input.length > 3 && input.length < 10) || 'Valid OTP, please', }, ]; const answers = (await inquirer.prompt(questions)) as any; @@ -133,7 +133,7 @@ export class NpmTarget extends BaseTarget { protected getNpmConfig(): NpmTargetOptions { const token = process.env.NPM_TOKEN; if (!token) { - throw new Error("NPM target: NPM_TOKEN not found in the environment"); + throw new Error('NPM target: NPM_TOKEN not found in the environment'); } const npmConfig: NpmTargetOptions = { @@ -150,8 +150,8 @@ export class NpmTarget extends BaseTarget { } } - const useOtp = (process.env.CRAFT_NPM_USE_OTP || "").toLowerCase(); - if (["1", "true", "yes"].indexOf(useOtp) > -1) { + const useOtp = (process.env.CRAFT_NPM_USE_OTP || '').toLowerCase(); + if (['1', 'true', 'yes'].indexOf(useOtp) > -1) { npmConfig.useOtp = true; } return npmConfig; @@ -167,13 +167,13 @@ export class NpmTarget extends BaseTarget { path: string, options: NpmPublishOptions ): Promise { - const args = ["publish"]; + const args = ['publish']; let bin: string; if (this.npmConfig.useYarn) { bin = YARN_BIN; args.push(`--new-version=${options.version}`); - args.push("--non-interactive"); + args.push('--non-interactive'); } else { bin = NPM_BIN; } @@ -187,9 +187,9 @@ export class NpmTarget extends BaseTarget { // In case we have a prerelease, there should never be a reason to publish // it with the latest tag in npm. if (isPreviewRelease(options.version)) { - logger.warn("Detected pre-release version for npm package!"); + logger.warn('Detected pre-release version for npm package!'); logger.warn('Adding tag "next" to not make it "latest" in registry.'); - args.push("--tag=next"); + args.push('--tag=next'); } return withTempFile((filePath) => { @@ -224,13 +224,13 @@ export class NpmTarget extends BaseTarget { * @param revision Git commit SHA to be published */ public async publish(version: string, revision: string): Promise { - logger.debug("Fetching artifact list..."); + logger.debug('Fetching artifact list...'); const packageFiles = await this.getArtifactsForRevision(revision, { includeNames: DEFAULT_PACKAGE_REGEX, }); if (!packageFiles.length) { - reportError("Cannot release to NPM: no packages found!"); + reportError('Cannot release to NPM: no packages found!'); return undefined; } @@ -247,6 +247,6 @@ export class NpmTarget extends BaseTarget { }) ); - logger.info("NPM release complete"); + logger.info('NPM release complete'); } } diff --git a/src/targets/nuget.ts b/src/targets/nuget.ts index 6390352b..c109442f 100644 --- a/src/targets/nuget.ts +++ b/src/targets/nuget.ts @@ -1,20 +1,20 @@ -import { logger as loggerRaw } from "../logger"; -import { TargetConfig } from "../schemas/project_config"; -import { ConfigurationError, reportError } from "../utils/errors"; -import { checkExecutableIsPresent, spawnProcess } from "../utils/system"; -import { BaseTarget } from "./base"; +import { logger as loggerRaw } from '../logger'; +import { TargetConfig } from '../schemas/project_config'; +import { ConfigurationError, reportError } from '../utils/errors'; +import { checkExecutableIsPresent, spawnProcess } from '../utils/system'; +import { BaseTarget } from './base'; import { BaseArtifactProvider, RemoteArtifact, -} from "../artifact_providers/base"; +} from '../artifact_providers/base'; -const logger = loggerRaw.withScope("[nuget]"); +const logger = loggerRaw.withScope('[nuget]'); /** Command to launch dotnet tools */ -export const NUGET_DOTNET_BIN = process.env.NUGET_DOTNET_BIN || "dotnet"; +export const NUGET_DOTNET_BIN = process.env.NUGET_DOTNET_BIN || 'dotnet'; /** Default Nuget registry URL */ -export const DEFAULT_NUGET_SERVER_URL = "https://api.nuget.org/v3/index.json"; +export const DEFAULT_NUGET_SERVER_URL = 'https://api.nuget.org/v3/index.json'; /** A regular expression used to find the package tarball */ const DEFAULT_NUGET_REGEX = /^.*\d\.\d.*\.nupkg$/; @@ -32,7 +32,7 @@ export interface NugetTargetOptions { */ export class NugetTarget extends BaseTarget { /** Target name */ - public readonly name: string = "nuget"; + public readonly name: string = 'nuget'; /** Target options */ public readonly nugetConfig: NugetTargetOptions; @@ -69,12 +69,12 @@ export class NugetTarget extends BaseTarget { */ public async uploadAsset(path: string): Promise { return spawnProcess(NUGET_DOTNET_BIN, [ - "nuget", - "push", + 'nuget', + 'push', path, - "--api-key", - "${NUGET_API_TOKEN}", - "--source", + '--api-key', + '${NUGET_API_TOKEN}', + '--source', this.nugetConfig.serverUrl, ]); } @@ -86,14 +86,14 @@ export class NugetTarget extends BaseTarget { * @param revision Git commit SHA to be published */ public async publish(_version: string, revision: string): Promise { - logger.debug("Fetching artifact list..."); + logger.debug('Fetching artifact list...'); const packageFiles = await this.getArtifactsForRevision(revision, { includeNames: DEFAULT_NUGET_REGEX, }); if (!packageFiles.length) { reportError( - "Cannot release to Nuget: there are no Nuget packages found!" + 'Cannot release to Nuget: there are no Nuget packages found!' ); } @@ -105,6 +105,6 @@ export class NugetTarget extends BaseTarget { }) ); - logger.info("Nuget release complete"); + logger.info('Nuget release complete'); } } diff --git a/src/targets/pypi.ts b/src/targets/pypi.ts index eec04183..18ee675d 100644 --- a/src/targets/pypi.ts +++ b/src/targets/pypi.ts @@ -1,16 +1,16 @@ -import { logger as loggerRaw } from "../logger"; -import { TargetConfig } from "../schemas/project_config"; +import { logger as loggerRaw } from '../logger'; +import { TargetConfig } from '../schemas/project_config'; import { BaseArtifactProvider, RemoteArtifact, -} from "../artifact_providers/base"; -import { ConfigurationError, reportError } from "../utils/errors"; -import { checkExecutableIsPresent, spawnProcess } from "../utils/system"; -import { BaseTarget } from "./base"; +} from '../artifact_providers/base'; +import { ConfigurationError, reportError } from '../utils/errors'; +import { checkExecutableIsPresent, spawnProcess } from '../utils/system'; +import { BaseTarget } from './base'; -const logger = loggerRaw.withScope("[pypi]"); +const logger = loggerRaw.withScope('[pypi]'); -const DEFAULT_TWINE_BIN = "twine"; +const DEFAULT_TWINE_BIN = 'twine'; /** * Command to launch twine @@ -35,7 +35,7 @@ export interface PypiTargetOptions { */ export class PypiTarget extends BaseTarget { /** Target name */ - public readonly name: string = "pypi"; + public readonly name: string = 'pypi'; /** Target options */ public readonly pypiConfig: PypiTargetOptions; @@ -57,7 +57,7 @@ export class PypiTarget extends BaseTarget { `Cannot perform PyPI release: missing credentials. Please use TWINE_USERNAME and TWINE_PASSWORD environment variables.`.replace( /^\s+/gm, - "" + '' ) ); } @@ -75,7 +75,7 @@ export class PypiTarget extends BaseTarget { */ public async uploadAsset(path: string): Promise { // TODO: Sign the package with "--sign" - return spawnProcess(TWINE_BIN, ["upload", path]); + return spawnProcess(TWINE_BIN, ['upload', path]); } /** @@ -88,13 +88,13 @@ export class PypiTarget extends BaseTarget { * @param revision Git commit SHA to be published */ public async publish(_version: string, revision: string): Promise { - logger.debug("Fetching artifact list..."); + logger.debug('Fetching artifact list...'); const packageFiles = await this.getArtifactsForRevision(revision, { includeNames: DEFAULT_PYPI_REGEX, }); if (!packageFiles.length) { - reportError("Cannot release to PyPI: no packages found"); + reportError('Cannot release to PyPI: no packages found'); return undefined; } @@ -106,6 +106,6 @@ export class PypiTarget extends BaseTarget { }) ); - logger.info("PyPI release complete"); + logger.info('PyPI release complete'); } } diff --git a/src/targets/registry.ts b/src/targets/registry.ts index d8b28c03..0548e073 100644 --- a/src/targets/registry.ts +++ b/src/targets/registry.ts @@ -1,48 +1,48 @@ -import { mapLimit } from "async"; -import * as Github from "@octokit/rest"; -import * as _ from "lodash"; -import simpleGit from "simple-git"; -import * as path from "path"; - -import { getGlobalGithubConfig } from "../config"; -import { logger as loggerRaw } from "../logger"; -import { GithubGlobalConfig, TargetConfig } from "../schemas/project_config"; -import { ConfigurationError, reportError } from "../utils/errors"; -import { withTempDir } from "../utils/files"; +import { mapLimit } from 'async'; +import * as Github from '@octokit/rest'; +import * as _ from 'lodash'; +import simpleGit from 'simple-git'; +import * as path from 'path'; + +import { getGlobalGithubConfig } from '../config'; +import { logger as loggerRaw } from '../logger'; +import { GithubGlobalConfig, TargetConfig } from '../schemas/project_config'; +import { ConfigurationError, reportError } from '../utils/errors'; +import { withTempDir } from '../utils/files'; import { getAuthUsername, getGithubApiToken, getGithubClient, GithubRemote, -} from "../utils/githubApi"; -import { renderTemplateSafe } from "../utils/strings"; -import { isPreviewRelease } from "../utils/version"; -import { stringToRegexp } from "../utils/filters"; -import { BaseTarget } from "./base"; +} from '../utils/githubApi'; +import { renderTemplateSafe } from '../utils/strings'; +import { isPreviewRelease } from '../utils/version'; +import { stringToRegexp } from '../utils/filters'; +import { BaseTarget } from './base'; import { RemoteArtifact, BaseArtifactProvider, MAX_DOWNLOAD_CONCURRENCY, -} from "../artifact_providers/base"; +} from '../artifact_providers/base'; import { castChecksums, ChecksumEntry, getArtifactChecksums, -} from "../utils/checksum"; -import * as registryUtils from "../utils/registry"; -import { getPackageDirPath } from "../utils/packagePath"; -import { isDryRun } from "../utils/helpers"; +} from '../utils/checksum'; +import * as registryUtils from '../utils/registry'; +import { getPackageDirPath } from '../utils/packagePath'; +import { isDryRun } from '../utils/helpers'; -const logger = loggerRaw.withScope("[registry]"); +const logger = loggerRaw.withScope('[registry]'); const DEFAULT_REGISTRY_REMOTE: GithubRemote = registryUtils.getRegistryGithubRemote(); /** Type of the registry package */ export enum RegistryPackageType { /** App is a generic package type that doesn't belong to any specific registry */ - APP = "app", + APP = 'app', /** SDK is a package hosted in one of public registries (PyPI, NPM, etc.) */ - SDK = "sdk", + SDK = 'sdk', } /** "registry" target options */ @@ -68,7 +68,7 @@ export interface RegistryConfig { */ export class RegistryTarget extends BaseTarget { /** Target name */ - public readonly name: string = "registry"; + public readonly name: string = 'registry'; /** Target options */ public readonly registryConfig: RegistryConfig; /** Github client */ @@ -104,7 +104,7 @@ export class RegistryTarget extends BaseTarget { let urlTemplate; if (registryType === RegistryPackageType.APP) { urlTemplate = this.config.urlTemplate; - if (urlTemplate && typeof urlTemplate !== "string") { + if (urlTemplate && typeof urlTemplate !== 'string') { throw new ConfigurationError( `Invalid "urlTemplate" specified: ${urlTemplate}` ); @@ -114,18 +114,18 @@ export class RegistryTarget extends BaseTarget { const releaseConfig = this.config.config; if (!releaseConfig) { throw new ConfigurationError( - "Cannot find configuration dictionary for release registry" + 'Cannot find configuration dictionary for release registry' ); } const canonicalName = releaseConfig.canonical; if (!canonicalName) { throw new ConfigurationError( - "Canonical name not found in the configuration" + 'Canonical name not found in the configuration' ); } const linkPrereleases = this.config.linkPrereleases || false; - if (typeof linkPrereleases !== "boolean") { + if (typeof linkPrereleases !== 'boolean') { throw new ConfigurationError('Invlaid type of "linkPrereleases"'); } @@ -134,7 +134,7 @@ export class RegistryTarget extends BaseTarget { const onlyIfPresentStr = this.config.onlyIfPresent || undefined; let onlyIfPresent; if (onlyIfPresentStr) { - if (typeof onlyIfPresentStr !== "string") { + if (typeof onlyIfPresentStr !== 'string') { throw new ConfigurationError('Invalid type of "onlyIfPresent"'); } onlyIfPresent = stringToRegexp(onlyIfPresentStr); @@ -173,7 +173,7 @@ export class RegistryTarget extends BaseTarget { const artifacts = await this.getArtifactsForRevision(revision); if (artifacts.length === 0) { - logger.warn("No artifacts found, not adding any links to the manifest"); + logger.warn('No artifacts found, not adding any links to the manifest'); return; } @@ -259,12 +259,12 @@ export class RegistryTarget extends BaseTarget { const artifacts = await this.getArtifactsForRevision(revision); if (artifacts.length === 0) { - logger.warn("No artifacts found, not adding any file data"); + logger.warn('No artifacts found, not adding any file data'); return; } logger.info( - "Adding extra data (checksums, download links) for available artifacts..." + 'Adding extra data (checksums, download links) for available artifacts...' ); const files: { [key: string]: any } = {}; @@ -342,8 +342,8 @@ export class RegistryTarget extends BaseTarget { const git = simpleGit(directory); logger.info(`Cloning "${remote.getRemoteString()}" to "${directory}"...`); await git.clone(remote.getRemoteStringWithAuth(), directory, [ - "--filter=tree:0", - "--single-branch", + '--filter=tree:0', + '--single-branch', ]); const packageDirPath = getPackageDirPath( @@ -370,18 +370,18 @@ export class RegistryTarget extends BaseTarget { ); // Commit - await git.add(["."]); + await git.add(['.']); await git.commit(`craft: release "${canonicalName}", version "${version}"`); // Ensure we are still up to date with upstream - await git.pull("origin", "master", ["--rebase"]); + await git.pull('origin', 'master', ['--rebase']); // Push! if (!isDryRun()) { logger.info(`Pushing the changes...`); - await git.push("origin", "master"); + await git.push('origin', 'master'); } else { - logger.info("[dry-run] Not pushing the changes."); + logger.info('[dry-run] Not pushing the changes.'); } } @@ -390,7 +390,7 @@ export class RegistryTarget extends BaseTarget { */ public async publish(version: string, revision: string): Promise { if (!this.registryConfig.linkPrereleases && isPreviewRelease(version)) { - logger.info("Preview release detected, skipping the target"); + logger.info('Preview release detected, skipping the target'); return undefined; } @@ -419,8 +419,8 @@ export class RegistryTarget extends BaseTarget { (directory) => this.pushVersionToRegistry(directory, remote, version, revision), true, - "craft-release-registry-" + 'craft-release-registry-' ); - logger.info("Release registry updated"); + logger.info('Release registry updated'); } } diff --git a/src/types/consola.d.ts b/src/types/consola.d.ts index a665ad3d..0d785f67 100644 --- a/src/types/consola.d.ts +++ b/src/types/consola.d.ts @@ -1,4 +1,4 @@ -declare module "consola" { +declare module 'consola' { interface Consola { fatal(...message: string[]): void; error(...message: string[]): void; diff --git a/src/types/mustache.d.ts b/src/types/mustache.d.ts index c7e43702..b1fb5386 100644 --- a/src/types/mustache.d.ts +++ b/src/types/mustache.d.ts @@ -3,7 +3,7 @@ // Definitions by: Mark Ashley Bell , Manuel Thalmann , Sentry.io // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -declare module "mustache" { +declare module 'mustache' { /** * Provides the functionality to render templates with `{{mustaches}}`. */ diff --git a/src/types/nvar.ts b/src/types/nvar.ts index 94948582..f969eb0f 100644 --- a/src/types/nvar.ts +++ b/src/types/nvar.ts @@ -1 +1 @@ -declare module "nvar"; +declare module 'nvar'; diff --git a/src/types/split.d.ts b/src/types/split.d.ts index f0bacabc..14d3e622 100644 --- a/src/types/split.d.ts +++ b/src/types/split.d.ts @@ -1 +1 @@ -declare module "split"; +declare module 'split'; diff --git a/src/types/unzipper.ts b/src/types/unzipper.ts index cc8d630f..59348d36 100644 --- a/src/types/unzipper.ts +++ b/src/types/unzipper.ts @@ -1 +1 @@ -declare module "unzipper"; +declare module 'unzipper'; diff --git a/src/utils/__fixtures__/gcsApi.ts b/src/utils/__fixtures__/gcsApi.ts index 7dde0315..20ed9f40 100644 --- a/src/utils/__fixtures__/gcsApi.ts +++ b/src/utils/__fixtures__/gcsApi.ts @@ -1,63 +1,63 @@ -import { RemoteArtifact } from "../../artifact_providers/base"; +import { RemoteArtifact } from '../../artifact_providers/base'; -export const dogsGHOrg = "dogs-rule"; +export const dogsGHOrg = 'dogs-rule'; -export const squirrelRepo = "squirrel-operations"; +export const squirrelRepo = 'squirrel-operations'; -export const squirrelBucket = "squirrel-chasing"; +export const squirrelBucket = 'squirrel-chasing'; export const squirrelSimulatorCommit = - "4d6169736579203c33203c3320436861726c6965"; + '4d6169736579203c33203c3320436861726c6965'; -export const squirrelStatsCommit = "3c3320446f67732061726520677265617421203c33"; +export const squirrelStatsCommit = '3c3320446f67732061726520677265617421203c33'; export const gcsCredsJSON = JSON.stringify({ - project_id: "o-u-t-s-i-d-e", - private_key: "DoGsArEgReAtSoMeSeCrEtStUfFhErE", - client_email: "might_huntress@dogs.com", - other_stuff: "can be anything", - tail_wagging: "true", - barking: "also VERY true", + project_id: 'o-u-t-s-i-d-e', + private_key: 'DoGsArEgReAtSoMeSeCrEtStUfFhErE', + client_email: 'might_huntress@dogs.com', + other_stuff: 'can be anything', + tail_wagging: 'true', + barking: 'also VERY true', }); export const squirrelStatsArtifact: RemoteArtifact = { - filename: "march-2020-stats.csv", - mimeType: "text/csv", + filename: 'march-2020-stats.csv', + mimeType: 'text/csv', storedFile: { - downloadFilepath: "captured-squirrels/march-2020-stats.csv", - filename: "march-2020-stats.csv", - lastUpdated: "2020-03-30T19:14:44.694Z", + downloadFilepath: 'captured-squirrels/march-2020-stats.csv', + filename: 'march-2020-stats.csv', + lastUpdated: '2020-03-30T19:14:44.694Z', size: 112112, }, }; -export const squirrelStatsLocalPath = "./temp/march-2020-stats.csv"; +export const squirrelStatsLocalPath = './temp/march-2020-stats.csv'; export const squirrelStatsBucketPath = { - path: "stats/2020/", + path: 'stats/2020/', }; export const squirrelSimulatorArtifact: RemoteArtifact = { - filename: "bundle.js", - mimeType: "application/json", + filename: 'bundle.js', + mimeType: 'application/json', storedFile: { - downloadFilepath: "squirrel-simulator/bundle.js", - filename: "bundle.js", - lastUpdated: "2020-03-30T19:14:44.694Z", + downloadFilepath: 'squirrel-simulator/bundle.js', + filename: 'bundle.js', + lastUpdated: '2020-03-30T19:14:44.694Z', size: 123112, }, }; -export const squirrelSimulatorLocalPath = "./dist/bundle.js"; +export const squirrelSimulatorLocalPath = './dist/bundle.js'; export const squirrelSimulatorBucketPath = { - path: "/simulator/v1.12.1/dist/", + path: '/simulator/v1.12.1/dist/', metadata: { cacheControl: `public, max-age=3600` }, }; export { squirrelSimulatorGCSFileObj, squirrelStatsGCSFileObj, -} from "./gcsFileObj"; +} from './gcsFileObj'; -export const tempDownloadDirectory = "./temp/"; +export const tempDownloadDirectory = './temp/'; diff --git a/src/utils/__fixtures__/gcsFileObj.ts b/src/utils/__fixtures__/gcsFileObj.ts index dae12262..32b36037 100644 --- a/src/utils/__fixtures__/gcsFileObj.ts +++ b/src/utils/__fixtures__/gcsFileObj.ts @@ -7,12 +7,12 @@ const acl = { owners: {}, readers: {}, writers: {}, - pathPrefix: "/acl", + pathPrefix: '/acl', }; const defaultAcl = { ...acl, - pathPrefix: "/defaultObjectAcl", + pathPrefix: '/defaultObjectAcl', }; const aclWithDefault = { @@ -21,21 +21,21 @@ const aclWithDefault = { }; const aclRoles = { - OWNER_ROLE: "OWNER", - READER_ROLE: "READER", - WRITER_ROLE: "WRITER", + OWNER_ROLE: 'OWNER', + READER_ROLE: 'READER', + WRITER_ROLE: 'WRITER', }; const scopes = [ - "https://www.googleapis.com/auth/iam", - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/devstorage.full_control", + 'https://www.googleapis.com/auth/iam', + 'https://www.googleapis.com/auth/cloud-platform', + 'https://www.googleapis.com/auth/devstorage.full_control', ]; const authClient = { jsonContent: { - client_email: "mighty_huntress@dogs.com", - private_key: "DoGsArEgReAtSoMeSeCrEtStUfFhErE", + client_email: 'mighty_huntress@dogs.com', + private_key: 'DoGsArEgReAtSoMeSeCrEtStUfFhErE', }, cachedCredential: { domain: null, @@ -43,42 +43,42 @@ const authClient = { _eventsCount: 0, transporter: {}, credentials: { - access_token: "IaMaGoOdDoGpLeAsElEtMeIn", - token_type: "Bearer", + access_token: 'IaMaGoOdDoGpLeAsElEtMeIn', + token_type: 'Bearer', expiry_date: 1585600265000, - refresh_token: "jwt-placeholder", + refresh_token: 'jwt-placeholder', }, certificateExpiry: null, refreshTokenPromises: {}, eagerRefreshThresholdMillis: 300000, - email: "mighty_huntress@dogs.com", - key: "DoGsArEgReAtSoMeSeCrEtStUfFhErE", + email: 'mighty_huntress@dogs.com', + key: 'DoGsArEgReAtSoMeSeCrEtStUfFhErE', scopes, gtoken: { - token: "IaMaGoOdDoGpLeAsElEtMeIn", + token: 'IaMaGoOdDoGpLeAsElEtMeIn', expiresAt: 1585600265000, rawToken: { - access_token: "IaMaGoOdDoGpLeAsElEtMeIn", + access_token: 'IaMaGoOdDoGpLeAsElEtMeIn', expires_in: 3599, - token_type: "Bearer", + token_type: 'Bearer', }, tokenExpires: null, - key: "DoGsArEgReAtSoMeSeCrEtStUfFhErE", - iss: "mighty_huntress@dogs.com", + key: 'DoGsArEgReAtSoMeSeCrEtStUfFhErE', + iss: 'mighty_huntress@dogs.com', scope: - "https://www.googleapis.com/auth/iam https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/devstorage.full_control", + 'https://www.googleapis.com/auth/iam https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/devstorage.full_control', }, }, - _cachedProjectId: "o-u-t-s-i-d-e", + _cachedProjectId: 'o-u-t-s-i-d-e', scopes, }; const storage = { - baseUrl: "https://www.googleapis.com/storage/v1", + baseUrl: 'https://www.googleapis.com/storage/v1', globalInterceptors: [], interceptors: [], - packageJson: "", - projectId: "o-u-t-s-i-d-e", + packageJson: '', + projectId: 'o-u-t-s-i-d-e', projectIdRequired: false, authClient, acl: aclRoles, @@ -89,18 +89,18 @@ const bucket = { _events: {}, _eventsCount: 0, metadata: {}, - baseUrl: "/b", + baseUrl: '/b', parent: storage, - id: "squirrel-chasing", + id: 'squirrel-chasing', methods: { create: true, }, interceptors: [], - name: "squirrel-chasing", + name: 'squirrel-chasing', storage, acl: aclWithDefault, iam: { - resourceId_: "buckets/[object Promise]", + resourceId_: 'buckets/[object Promise]', }, }; @@ -109,34 +109,34 @@ export const squirrelStatsGCSFileObj = { _events: {}, _eventsCount: 0, metadata: { - kind: "storage#object", - id: "squirrel-chasing/captured-squirrels/march-2020-stats.csv/12312012", + kind: 'storage#object', + id: 'squirrel-chasing/captured-squirrels/march-2020-stats.csv/12312012', selfLink: - "https://www.googleapis.com/storage/v1/b/squirrel-chasing/o/captured-squirrels%2Fmarch-2020-stats.csv", + 'https://www.googleapis.com/storage/v1/b/squirrel-chasing/o/captured-squirrels%2Fmarch-2020-stats.csv', mediaLink: - "https://www.googleapis.com/download/storage/v1/b/squirrel-chasing/o/captured-squirrels%2Fmarch-2020-stats.csv?generation=12312012&alt=media", - name: "captured-squirrels/march-2020-stats.csv", - bucket: "squirrel-chasing", - generation: "12312012", - metageneration: "1", - contentType: "text/csv", - storageClass: "STANDARD", - size: "112112", - md5Hash: "DOX0leRinotMTM7EGGXpjQ==", - crc32c: "fVcyCg==", - etag: "CI/UrJz0wugCEAE=", - timeCreated: "2020-03-30T19:14:44.694Z", - updated: "2020-03-30T19:14:44.694Z", - timeStorageClassUpdated: "2020-03-30T19:14:44.694Z", + 'https://www.googleapis.com/download/storage/v1/b/squirrel-chasing/o/captured-squirrels%2Fmarch-2020-stats.csv?generation=12312012&alt=media', + name: 'captured-squirrels/march-2020-stats.csv', + bucket: 'squirrel-chasing', + generation: '12312012', + metageneration: '1', + contentType: 'text/csv', + storageClass: 'STANDARD', + size: '112112', + md5Hash: 'DOX0leRinotMTM7EGGXpjQ==', + crc32c: 'fVcyCg==', + etag: 'CI/UrJz0wugCEAE=', + timeCreated: '2020-03-30T19:14:44.694Z', + updated: '2020-03-30T19:14:44.694Z', + timeStorageClassUpdated: '2020-03-30T19:14:44.694Z', }, - baseUrl: "/o", + baseUrl: '/o', parent: bucket, - id: "captured-squirrels%2Fmarch-2020-stats.csv", + id: 'captured-squirrels%2Fmarch-2020-stats.csv', methods: {}, interceptors: [], bucket, storage, - name: "captured-squirrels/march-2020-stats.csv", + name: 'captured-squirrels/march-2020-stats.csv', acl, }; @@ -145,33 +145,33 @@ export const squirrelSimulatorGCSFileObj = { _events: {}, _eventsCount: 0, metadata: { - kind: "storage#object", - id: "squirrel-chasing/squirrel-simulator/bundle.js/11212012", + kind: 'storage#object', + id: 'squirrel-chasing/squirrel-simulator/bundle.js/11212012', selfLink: - "https://www.googleapis.com/storage/v1/b/squirrel-chasing/o/squirrel-simulator%2Fbundle.js", + 'https://www.googleapis.com/storage/v1/b/squirrel-chasing/o/squirrel-simulator%2Fbundle.js', mediaLink: - "https://www.googleapis.com/download/storage/v1/b/squirrel-chasing/o/squirrel-simulator%2Fbundle.js?generation=11212012&alt=media", - name: "squirrel-simulator/bundle.js", - bucket: "squirrel-chasing", - generation: "11212012", - metageneration: "1", - contentType: "application/javascript", - storageClass: "STANDARD", - size: "123112", - md5Hash: "DOX0leRinotMTM7EGGXpjQ==", - crc32c: "fVcyCg==", - etag: "CI/UrJz0wugCEAE=", - timeCreated: "2020-03-30T19:14:44.694Z", - updated: "2020-03-30T19:14:44.694Z", - timeStorageClassUpdated: "2020-03-30T19:14:44.694Z", + 'https://www.googleapis.com/download/storage/v1/b/squirrel-chasing/o/squirrel-simulator%2Fbundle.js?generation=11212012&alt=media', + name: 'squirrel-simulator/bundle.js', + bucket: 'squirrel-chasing', + generation: '11212012', + metageneration: '1', + contentType: 'application/javascript', + storageClass: 'STANDARD', + size: '123112', + md5Hash: 'DOX0leRinotMTM7EGGXpjQ==', + crc32c: 'fVcyCg==', + etag: 'CI/UrJz0wugCEAE=', + timeCreated: '2020-03-30T19:14:44.694Z', + updated: '2020-03-30T19:14:44.694Z', + timeStorageClassUpdated: '2020-03-30T19:14:44.694Z', }, - baseUrl: "/o", + baseUrl: '/o', parent: bucket, - id: "squirrel-simulator%2Fbundle.js", + id: 'squirrel-simulator%2Fbundle.js', methods: {}, interceptors: [], bucket, storage, - name: "squirrel-simulator/bundle.js", + name: 'squirrel-simulator/bundle.js', acl, }; diff --git a/src/utils/__tests__/async.test.ts b/src/utils/__tests__/async.test.ts index 4f956d0e..ab97cb5e 100644 --- a/src/utils/__tests__/async.test.ts +++ b/src/utils/__tests__/async.test.ts @@ -1,16 +1,16 @@ -import { filterAsync, forEachChained, promiseProps } from "../async"; -import { logger } from "../../logger"; +import { filterAsync, forEachChained, promiseProps } from '../async'; +import { logger } from '../../logger'; -jest.mock("../../logger"); +jest.mock('../../logger'); -describe("filterAsync", () => { - test("filters with sync predicate", async () => { +describe('filterAsync', () => { + test('filters with sync predicate', async () => { expect.assertions(1); const filtered = await filterAsync([1, 2, 3, 4], (i) => i > 2); expect(filtered).toEqual([3, 4]); }); - test("filters with async predicate", async () => { + test('filters with async predicate', async () => { expect.assertions(1); const predicate = (i: number) => @@ -21,7 +21,7 @@ describe("filterAsync", () => { expect(filtered).toEqual([3, 4]); }); - test("passes filter arguments to the predicate", async () => { + test('passes filter arguments to the predicate', async () => { expect.assertions(1); const arr = [1]; @@ -31,10 +31,10 @@ describe("filterAsync", () => { expect(predicate).toHaveBeenCalledWith(1, 0, arr); }); - test("passes this to the predicate", async () => { + test('passes this to the predicate', async () => { expect.assertions(1); - const that = { key: "value" }; + const that = { key: 'value' }; await filterAsync( [1], function predicate(): any { @@ -45,45 +45,45 @@ describe("filterAsync", () => { }); }); -describe("promiseProps", () => { - test("awaits an empty object", async () => { +describe('promiseProps', () => { + test('awaits an empty object', async () => { expect.assertions(1); const result = await promiseProps({}); expect(result).toEqual({}); }); - test("awaits a plain object", async () => { + test('awaits a plain object', async () => { expect.assertions(1); - const result = await promiseProps({ foo: "foo", bar: 42 }); - expect(result).toEqual({ foo: "foo", bar: 42 }); + const result = await promiseProps({ foo: 'foo', bar: 42 }); + expect(result).toEqual({ foo: 'foo', bar: 42 }); }); - test("awaits an object with promises", async () => { + test('awaits an object with promises', async () => { expect.assertions(1); const result = await promiseProps({ bar: Promise.resolve(42), - foo: Promise.resolve("foo"), + foo: Promise.resolve('foo'), }); - expect(result).toEqual({ foo: "foo", bar: 42 }); + expect(result).toEqual({ foo: 'foo', bar: 42 }); }); }); -describe("forEachChained", () => { - test("invokes synchronous actions", async () => { +describe('forEachChained', () => { + test('invokes synchronous actions', async () => { expect.assertions(1); const fun = jest.fn(); - const arr = ["a", "b", "c"]; + const arr = ['a', 'b', 'c']; await forEachChained(arr, fun); expect(fun.mock.calls).toEqual([ - ["a", 0, arr], - ["b", 1, arr], - ["c", 2, arr], + ['a', 0, arr], + ['b', 1, arr], + ['c', 2, arr], ]); }); - test("invokes asynchronous actions sequentially", async () => { + test('invokes asynchronous actions sequentially', async () => { expect.assertions(1); const fun = jest.fn(); @@ -101,10 +101,10 @@ describe("forEachChained", () => { ]); }); - test("passes this to the action", async () => { + test('passes this to the action', async () => { expect.assertions(1); - const that = { "1": 2 }; + const that = { '1': 2 }; await forEachChained( [1], function action(): void { @@ -114,26 +114,26 @@ describe("forEachChained", () => { ); }); - describe("sync and async iteratees in regular and dry-run mode", () => { - const arr = ["first", "second", "third", "fourth"]; + describe('sync and async iteratees in regular and dry-run mode', () => { + const arr = ['first', 'second', 'third', 'fourth']; function syncIteratee(arrEntry: string): string { logger.debug(`Processing array entry \`${arrEntry}\``); - if (arrEntry === "second" || arrEntry === "fourth") { - throw new Error("drat"); + if (arrEntry === 'second' || arrEntry === 'fourth') { + throw new Error('drat'); } else { - return "yay!"; + return 'yay!'; } } function asyncIteratee(arrEntry: string): Promise { logger.debug(`Processing array entry \`${arrEntry}\``); - if (arrEntry === "second" || arrEntry === "fourth") { - return Promise.reject(new Error("drat")); + if (arrEntry === 'second' || arrEntry === 'fourth') { + return Promise.reject(new Error('drat')); } else { - return Promise.resolve("yay!"); + return Promise.resolve('yay!'); } } @@ -144,14 +144,14 @@ describe("forEachChained", () => { // check that the error does actually get thrown, the first time it hits a // problematic entry - await expect(forEachChained(arr, iteratee)).rejects.toThrowError("drat"); + await expect(forEachChained(arr, iteratee)).rejects.toThrowError('drat'); expect(logger.debug).toHaveBeenCalledWith( - "Processing array entry `second`" + 'Processing array entry `second`' ); // we didn't get this far expect(logger.debug).not.toHaveBeenCalledWith( - "Processing array entry `third`" + 'Processing array entry `third`' ); } @@ -163,12 +163,12 @@ describe("forEachChained", () => { // check that it logs the error rather than throws it await expect(forEachChained(arr, iteratee)).resolves.not.toThrowError(); expect(logger.error).toHaveBeenCalledWith( - expect.stringContaining("drat") + expect.stringContaining('drat') ); // check that it's gotten all the way through the array expect(logger.debug).toHaveBeenCalledWith( - "Processing array entry `fourth`" + 'Processing array entry `fourth`' ); } @@ -176,21 +176,21 @@ describe("forEachChained", () => { delete process.env.DRY_RUN; }); - it("blows up the first time sync iteratee errors (non-dry-run mode)", async () => { + it('blows up the first time sync iteratee errors (non-dry-run mode)', async () => { await regularModeExpectCheck(syncIteratee); }); - it("blows up the first time async iteratee errors (non-dry-run mode)", async () => { + it('blows up the first time async iteratee errors (non-dry-run mode)', async () => { await regularModeExpectCheck(asyncIteratee); }); - it("logs error but keeps going if in dry-run mode - sync iteratee", async () => { - process.env.DRY_RUN = "true"; + it('logs error but keeps going if in dry-run mode - sync iteratee', async () => { + process.env.DRY_RUN = 'true'; await dryrunModeExpectCheck(syncIteratee); }); - it("logs error but keeps going if in dry-run mode - async iteratee", async () => { - process.env.DRY_RUN = "true"; + it('logs error but keeps going if in dry-run mode - async iteratee', async () => { + process.env.DRY_RUN = 'true'; await dryrunModeExpectCheck(asyncIteratee); }); }); // end describe('sync and async iteratees in regular and dry-run mode') diff --git a/src/utils/__tests__/awsLambdaLayerManager.test.ts b/src/utils/__tests__/awsLambdaLayerManager.test.ts index 7235b98e..7580361b 100644 --- a/src/utils/__tests__/awsLambdaLayerManager.test.ts +++ b/src/utils/__tests__/awsLambdaLayerManager.test.ts @@ -1,65 +1,65 @@ -import { DescribeRegionsCommandOutput } from "@aws-sdk/client-ec2"; -import * as awsManager from "../awsLambdaLayerManager"; +import { DescribeRegionsCommandOutput } from '@aws-sdk/client-ec2'; +import * as awsManager from '../awsLambdaLayerManager'; -const CANONICAL_SEPARATOR = ":"; +const CANONICAL_SEPARATOR = ':'; const COMPATIBLE_RUNTIME_DATA = { - name: "test runtime", - versions: ["test version 1", "test version 2"], + name: 'test runtime', + versions: ['test version 1', 'test version 2'], }; -const AWS_TEST_REGIONS = ["test aws region 1", "test aws region 2"]; +const AWS_TEST_REGIONS = ['test aws region 1', 'test aws region 2']; /** The default region used to fetch all available AWS regions. */ -const DEFAULT_REGION = "us-east-2"; +const DEFAULT_REGION = 'us-east-2'; function getTestAwsLambdaLayerManager(): awsManager.AwsLambdaLayerManager { return new awsManager.AwsLambdaLayerManager( COMPATIBLE_RUNTIME_DATA, - "test layer name", - "test license", + 'test layer name', + 'test license', Buffer.alloc(0), AWS_TEST_REGIONS ); } -describe("canonical", () => { - test("get canonical name", () => { +describe('canonical', () => { + test('get canonical name', () => { const manager = getTestAwsLambdaLayerManager(); const canonicalSuffix = manager .getCanonicalName() .split(CANONICAL_SEPARATOR)[1]; - expect(canonicalSuffix).toBe("test runtime"); + expect(canonicalSuffix).toBe('test runtime'); }); }); -describe("utils", () => { - test("account from arn", () => { - const testAccount = "ACCOUNT_NUMBER"; +describe('utils', () => { + test('account from arn', () => { + const testAccount = 'ACCOUNT_NUMBER'; const testArn = - "arn:aws:lambda:region:" + testAccount + ":layer:layerName:version"; + 'arn:aws:lambda:region:' + testAccount + ':layer:layerName:version'; expect(awsManager.getAccountFromArn(testArn)).toBe(testAccount); }); - test("get regions", async () => { + test('get regions', async () => { const regions = await awsManager.getRegionsFromAws(); expect(regions).toBe(DEFAULT_REGION); }); - test("extract region names", () => { - const testRegionName1 = "eu-north-1"; - const testRegionName2 = "ap-south-1"; + test('extract region names', () => { + const testRegionName1 = 'eu-north-1'; + const testRegionName2 = 'ap-south-1'; const regionsToExtract = { Regions: [ { - Endpoint: "ec2.eu-north-1.amazonaws.com", + Endpoint: 'ec2.eu-north-1.amazonaws.com', RegionName: testRegionName1, - OptInStatus: "opt-in-not-required", + OptInStatus: 'opt-in-not-required', }, { - Endpoint: "ec2.ap-south-1.amazonaws.com", + Endpoint: 'ec2.ap-south-1.amazonaws.com', RegionName: testRegionName2, - OptInStatus: "opt-in-not-required", + OptInStatus: 'opt-in-not-required', }, ], }; @@ -73,15 +73,15 @@ describe("utils", () => { }); }); -describe("layer publishing", () => { - test("publish to single region", async () => { - const regionTest = "region-test"; +describe('layer publishing', () => { + test('publish to single region', async () => { + const regionTest = 'region-test'; const manager = getTestAwsLambdaLayerManager(); const publishedLayer = await manager.publishLayerToRegion(regionTest); expect(publishedLayer.region).toStrictEqual(regionTest); }); - test("publish to all regions", async () => { + test('publish to all regions', async () => { const manager = getTestAwsLambdaLayerManager(); const pubishedLayers = await manager.publishToAllRegions(); const publishedRegions = pubishedLayers.map((layer) => layer.region); diff --git a/src/utils/__tests__/changes.test.ts b/src/utils/__tests__/changes.test.ts index 1211cd2c..6714ccc7 100644 --- a/src/utils/__tests__/changes.test.ts +++ b/src/utils/__tests__/changes.test.ts @@ -1,20 +1,20 @@ /* eslint-env jest */ -import { findChangeset, removeChangeset, prependChangeset } from "../changes"; +import { findChangeset, removeChangeset, prependChangeset } from '../changes'; -describe("findChangeset", () => { +describe('findChangeset', () => { const sampleChangeset = { - body: "this is a test", - name: "Version 1.0.0", + body: 'this is a test', + name: 'Version 1.0.0', }; test.each([ [ - "regular", + 'regular', `# Changelog\n## ${sampleChangeset.name}\n${sampleChangeset.body}\n`, ], [ - "ignore date in parentheses", + 'ignore date in parentheses', `# Changelog ## 1.0.1 newer @@ -27,7 +27,7 @@ describe("findChangeset", () => { `, ], [ - "extracts a change between headings", + 'extracts a change between headings', `# Changelog ## 1.0.1 newer @@ -40,11 +40,11 @@ describe("findChangeset", () => { `, ], [ - "extracts changes from underlined headings", + 'extracts changes from underlined headings', `Changelog\n====\n${sampleChangeset.name}\n----\n${sampleChangeset.body}\n`, ], [ - "extracts changes from alternating headings", + 'extracts changes from alternating headings', `# Changelog ## 1.0.1 newer @@ -57,14 +57,14 @@ describe("findChangeset", () => { older `, ], - ])("should extract %s", (_testName, markdown) => { - expect(findChangeset(markdown, "v1.0.0")).toEqual(sampleChangeset); + ])('should extract %s', (_testName, markdown) => { + expect(findChangeset(markdown, 'v1.0.0')).toEqual(sampleChangeset); }); - test("supports sub-headings", () => { + test('supports sub-headings', () => { const changeset = { - body: "### Features\nthis is a test", - name: "Version 1.0.0", + body: '### Features\nthis is a test', + name: 'Version 1.0.0', }; const markdown = `# Changelog @@ -72,13 +72,13 @@ describe("findChangeset", () => { ${changeset.body} `; - expect(findChangeset(markdown, "v1.0.0")).toEqual(changeset); + expect(findChangeset(markdown, 'v1.0.0')).toEqual(changeset); }); test.each([ - ["changeset cannot be found", "v1.0.0"], - ["invalid version", "not a version"], - ])("should return null on %s", (_testName, version) => { + ['changeset cannot be found', 'v1.0.0'], + ['invalid version', 'not a version'], + ])('should return null on %s', (_testName, version) => { const markdown = `# Changelog ## 1.0.1 newer @@ -92,8 +92,8 @@ describe("findChangeset", () => { test.each([ [ - "remove from the top", - "1.0.1", + 'remove from the top', + '1.0.1', `# Changelog 1.0.0 ------- @@ -107,8 +107,8 @@ test.each([ `, ], [ - "remove from the middle", - "0.9.1", + 'remove from the middle', + '0.9.1', `# Changelog ## 1.0.1 newer @@ -122,8 +122,8 @@ test.each([ `, ], [ - "remove from underlined", - "1.0.0", + 'remove from underlined', + '1.0.0', `# Changelog ## 1.0.1 newer @@ -136,8 +136,8 @@ test.each([ `, ], [ - "remove from the bottom", - "0.9.0", + 'remove from the bottom', + '0.9.0', `# Changelog ## 1.0.1 newer @@ -152,8 +152,8 @@ test.each([ `, ], [ - "not remove missing", - "non-existent version", + 'not remove missing', + 'non-existent version', `# Changelog ## 1.0.1 newer @@ -170,8 +170,8 @@ test.each([ `, ], [ - "not remove empty", - "", + 'not remove empty', + '', `# Changelog ## 1.0.1 newer @@ -187,7 +187,7 @@ test.each([ older `, ], -])("remove changeset should %s", (_testName, header, expected) => { +])('remove changeset should %s', (_testName, header, expected) => { const markdown = `# Changelog ## 1.0.1 newer @@ -208,45 +208,45 @@ test.each([ test.each([ [ - "prepend to empty text", - "", - "## 2.0.0\n\nrewrote everything from scratch\n\n", + 'prepend to empty text', + '', + '## 2.0.0\n\nrewrote everything from scratch\n\n', ], [ - "prepend without top-level header", - "## 1.0.0\n\nthis is a test\n", - "## 2.0.0\n\nrewrote everything from scratch\n\n## 1.0.0\n\nthis is a test\n", + 'prepend without top-level header', + '## 1.0.0\n\nthis is a test\n', + '## 2.0.0\n\nrewrote everything from scratch\n\n## 1.0.0\n\nthis is a test\n', ], [ - "prepend after top-level header (empty body)", - "# Changelog\n", - "# Changelog\n## 2.0.0\n\nrewrote everything from scratch\n\n", + 'prepend after top-level header (empty body)', + '# Changelog\n', + '# Changelog\n## 2.0.0\n\nrewrote everything from scratch\n\n', ], [ - "prepend after top-level header", - "# Changelog\n\n## 1.0.0\n\nthis is a test\n", - "# Changelog\n\n## 2.0.0\n\nrewrote everything from scratch\n\n## 1.0.0\n\nthis is a test\n", + 'prepend after top-level header', + '# Changelog\n\n## 1.0.0\n\nthis is a test\n', + '# Changelog\n\n## 2.0.0\n\nrewrote everything from scratch\n\n## 1.0.0\n\nthis is a test\n', ], [ - "prepend with underlined when detected", - "# Changelog\n\n1.0.0\n-----\n\nthis is a test\n", - "# Changelog\n\n2.0.0\n-----\n\nrewrote everything from scratch\n\n1.0.0\n-----\n\nthis is a test\n", + 'prepend with underlined when detected', + '# Changelog\n\n1.0.0\n-----\n\nthis is a test\n', + '# Changelog\n\n2.0.0\n-----\n\nrewrote everything from scratch\n\n1.0.0\n-----\n\nthis is a test\n', ], [ - "prepend with consistent padding with the rest", - "# Changelog\n\n ## 1.0.0\n\n this is a test\n", - "# Changelog\n\n ## 2.0.0\n\n rewrote everything from scratch\n\n ## 1.0.0\n\n this is a test\n", + 'prepend with consistent padding with the rest', + '# Changelog\n\n ## 1.0.0\n\n this is a test\n', + '# Changelog\n\n ## 2.0.0\n\n rewrote everything from scratch\n\n ## 1.0.0\n\n this is a test\n', ], [ - "prepend with consistent padding with the rest (underlined)", - "# Changelog\n\n 1.0.0\n-----\n\n this is a test\n", - "# Changelog\n\n 2.0.0\n-----\n\n rewrote everything from scratch\n\n 1.0.0\n-----\n\n this is a test\n", + 'prepend with consistent padding with the rest (underlined)', + '# Changelog\n\n 1.0.0\n-----\n\n this is a test\n', + '# Changelog\n\n 2.0.0\n-----\n\n rewrote everything from scratch\n\n 1.0.0\n-----\n\n this is a test\n', ], -])("prependChangeset should %s", (_testName, markdown, expected) => { +])('prependChangeset should %s', (_testName, markdown, expected) => { expect( prependChangeset(markdown, { - body: "rewrote everything from scratch", - name: "2.0.0", + body: 'rewrote everything from scratch', + name: '2.0.0', }) ).toEqual(expected); }); diff --git a/src/utils/__tests__/env.test.ts b/src/utils/__tests__/env.test.ts index fbc69a63..7962f928 100644 --- a/src/utils/__tests__/env.test.ts +++ b/src/utils/__tests__/env.test.ts @@ -1,22 +1,22 @@ -import { writeFileSync } from "fs"; -import { join } from "path"; -const os = require("os"); +import { writeFileSync } from 'fs'; +import { join } from 'path'; +const os = require('os'); -import * as config from "../../config"; +import * as config from '../../config'; import { checkEnvForPrerequisite, readEnvironmentConfig, ENV_FILE_NAME, -} from "../env"; -import { ConfigurationError } from "../errors"; -import { logger } from "../../logger"; -import { withTempDir } from "../files"; +} from '../env'; +import { ConfigurationError } from '../errors'; +import { logger } from '../../logger'; +import { withTempDir } from '../files'; -jest.mock("../../logger"); -const homedirMock = jest.spyOn(os, "homedir"); -const getConfigFileDirMock = jest.spyOn(config, "getConfigFileDir"); +jest.mock('../../logger'); +const homedirMock = jest.spyOn(os, 'homedir'); +const getConfigFileDirMock = jest.spyOn(config, 'getConfigFileDir'); -describe("env utils functions", () => { +describe('env utils functions', () => { const cleanEnv = { ...process.env }; beforeEach(() => { @@ -24,141 +24,141 @@ describe("env utils functions", () => { jest.resetAllMocks(); }); - describe("checkEnvForPrerequisite", () => { - it("runs", () => { - process.env.DOGS = "RULE"; // just to prevent the function erroring - checkEnvForPrerequisite({ name: "DOGS" }); + describe('checkEnvForPrerequisite', () => { + it('runs', () => { + process.env.DOGS = 'RULE'; // just to prevent the function erroring + checkEnvForPrerequisite({ name: 'DOGS' }); expect(logger.debug).toHaveBeenCalledWith( - expect.stringContaining("Checking for environment variable DOGS") + expect.stringContaining('Checking for environment variable DOGS') ); }); - describe("no legacy name", () => { - it("finds correctly set var", () => { - process.env.DOGS = "RULE"; - checkEnvForPrerequisite({ name: "DOGS" }); + describe('no legacy name', () => { + it('finds correctly set var', () => { + process.env.DOGS = 'RULE'; + checkEnvForPrerequisite({ name: 'DOGS' }); expect(logger.debug).toHaveBeenCalledWith(`Found DOGS`); }); - it("errors if var not set", () => { - expect(() => checkEnvForPrerequisite({ name: "DOGS" })).toThrowError( + it('errors if var not set', () => { + expect(() => checkEnvForPrerequisite({ name: 'DOGS' })).toThrowError( ConfigurationError ); }); }); // end describe('no legacy name') - describe("with legacy name", () => { - it("handles both new and legacy variable being set", () => { - process.env.DOGS = "RULE"; - process.env.CATS = "DROOL"; - checkEnvForPrerequisite({ name: "DOGS", legacyName: "CATS" }); + describe('with legacy name', () => { + it('handles both new and legacy variable being set', () => { + process.env.DOGS = 'RULE'; + process.env.CATS = 'DROOL'; + checkEnvForPrerequisite({ name: 'DOGS', legacyName: 'CATS' }); expect(logger.warn).toHaveBeenCalledWith( `When searching configuration files and your environment, found DOGS ` + `but also found legacy CATS. Do you mean to be using both?` ); }); - it("handles only new variable being set", () => { - process.env.DOGS = "RULE"; - checkEnvForPrerequisite({ name: "DOGS", legacyName: "CATS" }); - expect(logger.debug).toHaveBeenCalledWith("Found DOGS"); + it('handles only new variable being set', () => { + process.env.DOGS = 'RULE'; + checkEnvForPrerequisite({ name: 'DOGS', legacyName: 'CATS' }); + expect(logger.debug).toHaveBeenCalledWith('Found DOGS'); }); - it("handles only legacy variable being set, and copies value to new variable", () => { - process.env.CATS = "DROOL"; - checkEnvForPrerequisite({ name: "DOGS", legacyName: "CATS" }); + it('handles only legacy variable being set, and copies value to new variable', () => { + process.env.CATS = 'DROOL'; + checkEnvForPrerequisite({ name: 'DOGS', legacyName: 'CATS' }); expect(logger.warn).toHaveBeenCalledWith( `Usage of CATS is deprecated, and will be removed in later versions. ` + `Please use DOGS instead.` ); - expect(process.env.DOGS).toEqual("DROOL"); + expect(process.env.DOGS).toEqual('DROOL'); }); - it("errors if neither is set", () => { + it('errors if neither is set', () => { expect(() => - checkEnvForPrerequisite({ name: "DOGS", legacyName: "CATS" }) + checkEnvForPrerequisite({ name: 'DOGS', legacyName: 'CATS' }) ).toThrowError(ConfigurationError); }); }); // end describe('with legacy name') - describe("multiple options", () => { - it("checks for multiple variables", () => { + describe('multiple options', () => { + it('checks for multiple variables', () => { // don't set either variable to force it to look for both (but that makes // it error, so `expect` the error to catch it so it doesn't break the // test) expect(() => - checkEnvForPrerequisite({ name: "MAISEY" }, { name: "CHARLIE" }) + checkEnvForPrerequisite({ name: 'MAISEY' }, { name: 'CHARLIE' }) ).toThrowError(ConfigurationError); expect(logger.debug).toHaveBeenCalledWith( `Checking for environment variable(s) MAISEY or CHARLIE` ); expect(logger.debug).toHaveBeenCalledWith( - expect.stringContaining("Checking for environment variable MAISEY") + expect.stringContaining('Checking for environment variable MAISEY') ); expect(logger.debug).toHaveBeenCalledWith( - expect.stringContaining("Checking for environment variable CHARLIE") + expect.stringContaining('Checking for environment variable CHARLIE') ); }); - it("is happy if either option is defined", () => { - process.env.MAISEY = "GOOD DOG"; + it('is happy if either option is defined', () => { + process.env.MAISEY = 'GOOD DOG'; expect(() => - checkEnvForPrerequisite({ name: "MAISEY" }, { name: "CHARLIE" }) + checkEnvForPrerequisite({ name: 'MAISEY' }, { name: 'CHARLIE' }) ).not.toThrowError(ConfigurationError); - expect(logger.debug).toHaveBeenCalledWith("Found MAISEY"); + expect(logger.debug).toHaveBeenCalledWith('Found MAISEY'); delete process.env.MAISEY; - process.env.CHARLIE = "ALSO GOOD DOG"; + process.env.CHARLIE = 'ALSO GOOD DOG'; expect(() => - checkEnvForPrerequisite({ name: "MAISEY" }, { name: "CHARLIE" }) + checkEnvForPrerequisite({ name: 'MAISEY' }, { name: 'CHARLIE' }) ).not.toThrowError(ConfigurationError); - expect(logger.debug).toHaveBeenCalledWith("Found CHARLIE"); + expect(logger.debug).toHaveBeenCalledWith('Found CHARLIE'); }); - it("throws if neither one is defined", () => { + it('throws if neither one is defined', () => { // skip defining vars here expect(() => - checkEnvForPrerequisite({ name: "MAISEY" }, { name: "CHARLIE" }) + checkEnvForPrerequisite({ name: 'MAISEY' }, { name: 'CHARLIE' }) ).toThrowError(ConfigurationError); }); - it("handles a mix of variables with and without legacy names", () => { - process.env.MAISEY = "GOOD DOG"; + it('handles a mix of variables with and without legacy names', () => { + process.env.MAISEY = 'GOOD DOG'; expect(() => checkEnvForPrerequisite( - { name: "MAISEY" }, - { name: "CHARLIE", legacyName: "OPAL" } + { name: 'MAISEY' }, + { name: 'CHARLIE', legacyName: 'OPAL' } ) ).not.toThrowError(ConfigurationError); - expect(logger.debug).toHaveBeenCalledWith("Found MAISEY"); + expect(logger.debug).toHaveBeenCalledWith('Found MAISEY'); delete process.env.MAISEY; - process.env.OPAL = "GOOD PUPPY"; + process.env.OPAL = 'GOOD PUPPY'; expect(() => checkEnvForPrerequisite( - { name: "MAISEY" }, - { name: "CHARLIE", legacyName: "OPAL" } + { name: 'MAISEY' }, + { name: 'CHARLIE', legacyName: 'OPAL' } ) ).not.toThrowError(ConfigurationError); expect(logger.warn).toHaveBeenCalledWith( `Usage of OPAL is deprecated, and will be removed in later versions. ` + `Please use CHARLIE instead.` ); - expect(process.env.CHARLIE).toEqual("GOOD PUPPY"); + expect(process.env.CHARLIE).toEqual('GOOD PUPPY'); }); }); // end describe('multiple variables') }); // end describe('checkEnvForPrerequisites') - describe("readEnvironmentConfig", () => { - const invalidDir = "/invalid/invalid"; + describe('readEnvironmentConfig', () => { + const invalidDir = '/invalid/invalid'; function writeConfigFileSync(directory: string): void { const outConfigFile = join(directory, config.CONFIG_FILE_NAME); - writeFileSync(outConfigFile, ""); + writeFileSync(outConfigFile, ''); } - test("calls homedir/findConfigFile", () => { - process.env.TEST_BLA = "123"; + test('calls homedir/findConfigFile', () => { + process.env.TEST_BLA = '123'; homedirMock.mockReturnValue(invalidDir); getConfigFileDirMock.mockReturnValue(invalidDir); @@ -167,11 +167,11 @@ describe("env utils functions", () => { expect(getConfigFileDirMock).toHaveBeenCalledTimes(1); expect(homedirMock).toHaveBeenCalledTimes(1); - expect(process.env.TEST_BLA).toBe("123"); + expect(process.env.TEST_BLA).toBe('123'); expect(ENV_FILE_NAME.length).toBeGreaterThanOrEqual(1); }); - test("checks the config directory", async () => { + test('checks the config directory', async () => { homedirMock.mockReturnValue(invalidDir); await withTempDir((directory) => { @@ -180,67 +180,67 @@ describe("env utils functions", () => { writeConfigFileSync(directory); const outFile = join(directory, ENV_FILE_NAME); - writeFileSync(outFile, "export TEST_BLA=234\nexport TEST_ANOTHER=345"); + writeFileSync(outFile, 'export TEST_BLA=234\nexport TEST_ANOTHER=345'); readEnvironmentConfig(); - expect(process.env.TEST_BLA).toBe("234"); + expect(process.env.TEST_BLA).toBe('234'); }); }); - test("checks home directory", async () => { + test('checks home directory', async () => { getConfigFileDirMock.mockReturnValue(invalidDir); await withTempDir((directory) => { homedirMock.mockReturnValue(directory); const outFile = join(directory, ENV_FILE_NAME); - writeFileSync(outFile, "export TEST_BLA=234\n"); + writeFileSync(outFile, 'export TEST_BLA=234\n'); readEnvironmentConfig(); - expect(process.env.TEST_BLA).toBe("234"); + expect(process.env.TEST_BLA).toBe('234'); }); }); - test("checks home directory first, and then the config directory", async () => { + test('checks home directory first, and then the config directory', async () => { await withTempDir(async (dir1) => { await withTempDir((dir2) => { homedirMock.mockReturnValue(dir1); const outHome = join(dir1, ENV_FILE_NAME); - writeFileSync(outHome, "export TEST_BLA=from_home"); + writeFileSync(outHome, 'export TEST_BLA=from_home'); getConfigFileDirMock.mockReturnValue(dir2); writeConfigFileSync(dir2); const configDirFile = join(dir2, ENV_FILE_NAME); - writeFileSync(configDirFile, "export TEST_BLA=from_config_dir"); + writeFileSync(configDirFile, 'export TEST_BLA=from_config_dir'); readEnvironmentConfig(); - expect(process.env.TEST_BLA).toBe("from_config_dir"); + expect(process.env.TEST_BLA).toBe('from_config_dir'); }); }); }); - test("does not overwrite existing variables by default", async () => { + test('does not overwrite existing variables by default', async () => { homedirMock.mockReturnValue(invalidDir); - process.env.TEST_BLA = "existing"; + process.env.TEST_BLA = 'existing'; await withTempDir((directory) => { getConfigFileDirMock.mockReturnValue(directory); const outFile = join(directory, ENV_FILE_NAME); - writeFileSync(outFile, "export TEST_BLA=new_value"); + writeFileSync(outFile, 'export TEST_BLA=new_value'); readEnvironmentConfig(); - expect(process.env.TEST_BLA).toBe("existing"); + expect(process.env.TEST_BLA).toBe('existing'); }); }); - test("overwrites existing variables if explicitly stated", async () => { + test('overwrites existing variables if explicitly stated', async () => { homedirMock.mockReturnValue(invalidDir); - process.env.TEST_BLA = "existing"; + process.env.TEST_BLA = 'existing'; await withTempDir((directory) => { getConfigFileDirMock.mockReturnValue(directory); @@ -248,11 +248,11 @@ describe("env utils functions", () => { writeConfigFileSync(directory); const outFile = join(directory, ENV_FILE_NAME); - writeFileSync(outFile, "export TEST_BLA=new_value"); + writeFileSync(outFile, 'export TEST_BLA=new_value'); readEnvironmentConfig(true); - expect(process.env.TEST_BLA).toBe("new_value"); + expect(process.env.TEST_BLA).toBe('new_value'); }); }); }); // end describe('readEnvironmentConfig') diff --git a/src/utils/__tests__/errors.test.ts b/src/utils/__tests__/errors.test.ts index ec73d26d..e4096229 100644 --- a/src/utils/__tests__/errors.test.ts +++ b/src/utils/__tests__/errors.test.ts @@ -1,20 +1,20 @@ -import { coerceType } from "../errors"; +import { coerceType } from '../errors'; -describe("coerceType", () => { - test("asserts a string correctly", async () => { - expect(coerceType("test", "string")).toBe("test"); +describe('coerceType', () => { + test('asserts a string correctly', async () => { + expect(coerceType('test', 'string')).toBe('test'); }); - test("asserts a number correctly", async () => { - expect(coerceType(123, "number")).toBe(123); + test('asserts a number correctly', async () => { + expect(coerceType(123, 'number')).toBe(123); }); - test("throws an error if the type is incorrect", async () => { - expect(() => coerceType(123, "function")).toThrowError(TypeError); + test('throws an error if the type is incorrect', async () => { + expect(() => coerceType(123, 'function')).toThrowError(TypeError); }); - test("throws an error with a custom message", async () => { - const customMsg = "custom message"; - expect(() => coerceType({}, "number", customMsg)).toThrowError(customMsg); + test('throws an error with a custom message', async () => { + const customMsg = 'custom message'; + expect(() => coerceType({}, 'number', customMsg)).toThrowError(customMsg); }); }); diff --git a/src/utils/__tests__/files.test.ts b/src/utils/__tests__/files.test.ts index bf966ce9..916cd7b8 100644 --- a/src/utils/__tests__/files.test.ts +++ b/src/utils/__tests__/files.test.ts @@ -1,25 +1,25 @@ -import { existsSync, rmdirSync } from "fs"; -import { join, resolve } from "path"; +import { existsSync, rmdirSync } from 'fs'; +import { join, resolve } from 'path'; -import { listFiles, withTempDir } from "../files"; +import { listFiles, withTempDir } from '../files'; -describe("listFiles", () => { - const testDir = resolve(__dirname, "../__fixtures__/listFiles"); - const testFiles = ["a", "b"].map((f) => join(testDir, f)); +describe('listFiles', () => { + const testDir = resolve(__dirname, '../__fixtures__/listFiles'); + const testFiles = ['a', 'b'].map((f) => join(testDir, f)); - test("returns only files", async () => { + test('returns only files', async () => { expect.assertions(1); const files = await listFiles(testDir); expect(files).toEqual(testFiles); }); }); -describe("withTempDir", () => { +describe('withTempDir', () => { async function testDirectories( callback: (arg: any) => any, cleanupEnabled = true ): Promise { - let directory = ""; + let directory = ''; try { await withTempDir((dir) => { directory = dir; @@ -38,25 +38,25 @@ describe("withTempDir", () => { } } - test("creates and removes synchronously", async () => { + test('creates and removes synchronously', async () => { expect.assertions(2); await testDirectories(() => true); }); - test("creates and removes on error", async () => { + test('creates and removes on error', async () => { try { expect.assertions(3); await testDirectories(() => { - throw new Error("fail"); + throw new Error('fail'); }); } catch (e) { - expect(e.message).toBe("fail"); + expect(e.message).toBe('fail'); } }); - test("creates and does not remove if cleanup flag is specified", async () => { + test('creates and does not remove if cleanup flag is specified', async () => { expect.assertions(2); - let tempDir = ""; + let tempDir = ''; await testDirectories((arg) => { tempDir = arg; }, false); @@ -64,29 +64,29 @@ describe("withTempDir", () => { rmdirSync(tempDir); }); - test("creates and removes on Promise resolution", async () => { + test('creates and removes on Promise resolution', async () => { expect.assertions(2); - await testDirectories(() => Promise.resolve("success")); + await testDirectories(() => Promise.resolve('success')); }); - test("creates and removes on Promise rejection", async () => { + test('creates and removes on Promise rejection', async () => { try { expect.assertions(3); - await testDirectories(() => Promise.reject(new Error("fail"))); + await testDirectories(() => Promise.reject(new Error('fail'))); } catch (e) { - expect(e.message).toBe("fail"); + expect(e.message).toBe('fail'); } }); - test("returns the callback return value synchronously", async () => { + test('returns the callback return value synchronously', async () => { expect.assertions(1); - const result = await withTempDir(() => "result"); - expect(result).toBe("result"); + const result = await withTempDir(() => 'result'); + expect(result).toBe('result'); }); - test("returns the callback return value asynchronously", async () => { + test('returns the callback return value asynchronously', async () => { expect.assertions(1); - const result = await withTempDir(() => Promise.resolve("result")); - expect(result).toBe("result"); + const result = await withTempDir(() => Promise.resolve('result')); + expect(result).toBe('result'); }); }); diff --git a/src/utils/__tests__/filters.test.ts b/src/utils/__tests__/filters.test.ts index 3ee38631..58bf55fe 100644 --- a/src/utils/__tests__/filters.test.ts +++ b/src/utils/__tests__/filters.test.ts @@ -1,30 +1,30 @@ -import { stringToRegexp } from "../filters"; +import { stringToRegexp } from '../filters'; -describe("stringToRegexp", () => { - test("converts string without special characters", () => { - expect(stringToRegexp("/simple/")).toEqual(/simple/); +describe('stringToRegexp', () => { + test('converts string without special characters', () => { + expect(stringToRegexp('/simple/')).toEqual(/simple/); }); - test("converts string with special characters", () => { - expect(stringToRegexp("/sim.le\\d+/")).toEqual(/sim.le\d+/); + test('converts string with special characters', () => { + expect(stringToRegexp('/sim.le\\d+/')).toEqual(/sim.le\d+/); }); - test("uses regexp modifiers", () => { - expect(stringToRegexp("/[!?]{2}\\w+/gi")).toEqual(/[!?]{2}\w+/gi); + test('uses regexp modifiers', () => { + expect(stringToRegexp('/[!?]{2}\\w+/gi')).toEqual(/[!?]{2}\w+/gi); }); - test("is not confused by multiple slashes", () => { - expect(stringToRegexp("/file1/file2/i")).toEqual(/file1\/file2/i); + test('is not confused by multiple slashes', () => { + expect(stringToRegexp('/file1/file2/i')).toEqual(/file1\/file2/i); }); - test("is source of regex what we think", () => { - expect(stringToRegexp("/none/").source).toEqual("none"); + test('is source of regex what we think', () => { + expect(stringToRegexp('/none/').source).toEqual('none'); }); - test("raises an error if the value is not surrounded by slashes", () => { + test('raises an error if the value is not surrounded by slashes', () => { expect.assertions(1); try { - stringToRegexp("no-slashes"); + stringToRegexp('no-slashes'); } catch (e) { expect(e.message).toMatch(/invalid regexp/i); } diff --git a/src/utils/__tests__/gcsAPI.test.ts b/src/utils/__tests__/gcsAPI.test.ts index ac8ccaab..f5e020d2 100644 --- a/src/utils/__tests__/gcsAPI.test.ts +++ b/src/utils/__tests__/gcsAPI.test.ts @@ -1,12 +1,12 @@ -import * as fs from "fs"; -import * as path from "path"; +import * as fs from 'fs'; +import * as path from 'path'; import { getGCSCredsFromEnv, CraftGCSClient, DEFAULT_UPLOAD_METADATA, -} from "../gcsApi"; -import { withTempFile, withTempDir } from "../files"; +} from '../gcsApi'; +import { withTempFile, withTempDir } from '../files'; import { dogsGHOrg, @@ -23,16 +23,16 @@ import { squirrelStatsGCSFileObj, squirrelStatsCommit, squirrelSimulatorGCSFileObj, -} from "../__fixtures__/gcsApi"; +} from '../__fixtures__/gcsApi'; /*************** mocks and other setup ***************/ -jest.mock("../../logger"); +jest.mock('../../logger'); const mockGCSUpload = jest.fn(); const mockGCSDownload = jest.fn(); const mockGCSGetFiles = jest.fn(); -jest.mock("@google-cloud/storage", () => ({ +jest.mock('@google-cloud/storage', () => ({ Bucket: jest.fn(() => ({ file: jest.fn(() => ({ download: mockGCSDownload })), getFiles: mockGCSGetFiles, @@ -41,22 +41,22 @@ jest.mock("@google-cloud/storage", () => ({ Storage: jest.fn(() => ({})), })); -const syncExistsSpy = jest.spyOn(fs, "existsSync"); +const syncExistsSpy = jest.spyOn(fs, 'existsSync'); const cleanEnv = { ...process.env }; const client = new CraftGCSClient({ bucketName: squirrelBucket, credentials: { - client_email: "mighty_huntress@dogs.com", - private_key: "DoGsArEgReAtSoMeSeCrEtStUfFhErE", + client_email: 'mighty_huntress@dogs.com', + private_key: 'DoGsArEgReAtSoMeSeCrEtStUfFhErE', }, - projectId: "o-u-t-s-i-d-e", + projectId: 'o-u-t-s-i-d-e', }); /*************** the actual tests ***************/ -describe("gcsApi module", () => { +describe('gcsApi module', () => { afterEach(() => { // in case we've modified the env in any way, reset it process.env = { ...cleanEnv }; @@ -66,21 +66,21 @@ describe("gcsApi module", () => { jest.clearAllMocks(); }); - describe("getGCSCredsFromEnv", () => { - it("pulls JSON creds from env", () => { + describe('getGCSCredsFromEnv', () => { + it('pulls JSON creds from env', () => { process.env.DOG_CREDS_JSON = gcsCredsJSON; const { project_id, client_email, private_key } = getGCSCredsFromEnv( - { name: "DOG_CREDS_JSON" }, - { name: "DOG_CREDS_PATH" } + { name: 'DOG_CREDS_JSON' }, + { name: 'DOG_CREDS_PATH' } ); - expect(project_id).toEqual("o-u-t-s-i-d-e"); - expect(client_email).toEqual("might_huntress@dogs.com"); - expect(private_key).toEqual("DoGsArEgReAtSoMeSeCrEtStUfFhErE"); + expect(project_id).toEqual('o-u-t-s-i-d-e'); + expect(client_email).toEqual('might_huntress@dogs.com'); + expect(private_key).toEqual('DoGsArEgReAtSoMeSeCrEtStUfFhErE'); }); - it("pulls filepath creds from env", async () => { + it('pulls filepath creds from env', async () => { // ensure that the assertions below actually happen, since they in an async // function expect.assertions(3); @@ -90,53 +90,53 @@ describe("gcsApi module", () => { process.env.DOG_CREDS_PATH = tempFilepath; const { project_id, client_email, private_key } = getGCSCredsFromEnv( - { name: "DOG_CREDS_JSON" }, - { name: "DOG_CREDS_PATH" } + { name: 'DOG_CREDS_JSON' }, + { name: 'DOG_CREDS_PATH' } ); - expect(project_id).toEqual("o-u-t-s-i-d-e"); - expect(client_email).toEqual("might_huntress@dogs.com"); - expect(private_key).toEqual("DoGsArEgReAtSoMeSeCrEtStUfFhErE"); + expect(project_id).toEqual('o-u-t-s-i-d-e'); + expect(client_email).toEqual('might_huntress@dogs.com'); + expect(private_key).toEqual('DoGsArEgReAtSoMeSeCrEtStUfFhErE'); }); }); - it("errors if neither JSON creds nor creds filepath provided", () => { + it('errors if neither JSON creds nor creds filepath provided', () => { // skip defining variables expect(() => { getGCSCredsFromEnv( - { name: "DOG_CREDS_JSON" }, - { name: "DOG_CREDS_PATH" } + { name: 'DOG_CREDS_JSON' }, + { name: 'DOG_CREDS_PATH' } ); - }).toThrowError("GCS credentials not found!"); + }).toThrowError('GCS credentials not found!'); }); - it("errors if given bogus JSON", () => { + it('errors if given bogus JSON', () => { process.env.DOG_CREDS_JSON = `Dogs!`; expect(() => { getGCSCredsFromEnv( - { name: "DOG_CREDS_JSON" }, - { name: "DOG_CREDS_PATH" } + { name: 'DOG_CREDS_JSON' }, + { name: 'DOG_CREDS_PATH' } ); - }).toThrowError("Error parsing JSON credentials"); + }).toThrowError('Error parsing JSON credentials'); }); - it("errors if creds file missing from given path", () => { - process.env.DOG_CREDS_PATH = "./iDontExist.json"; + it('errors if creds file missing from given path', () => { + process.env.DOG_CREDS_PATH = './iDontExist.json'; // make sure it won't find the file syncExistsSpy.mockReturnValueOnce(false); expect(() => { getGCSCredsFromEnv( - { name: "DOG_CREDS_JSON" }, - { name: "DOG_CREDS_PATH" } + { name: 'DOG_CREDS_JSON' }, + { name: 'DOG_CREDS_PATH' } ); - }).toThrowError("File does not exist: `./iDontExist.json`!"); + }).toThrowError('File does not exist: `./iDontExist.json`!'); }); - it("errors if necessary field missing", () => { + it('errors if necessary field missing', () => { process.env.DOG_CREDS_JSON = `{ "project_id": "o-u-t-s-i-d-e", "private_key": "DoGsArEgReAtSoMeSeCrEtStUfFhErE" @@ -144,16 +144,16 @@ describe("gcsApi module", () => { expect(() => { getGCSCredsFromEnv( - { name: "DOG_CREDS_JSON" }, - { name: "DOG_CREDS_PATH" } + { name: 'DOG_CREDS_JSON' }, + { name: 'DOG_CREDS_PATH' } ); - }).toThrowError("GCS credentials missing `client_email`!"); + }).toThrowError('GCS credentials missing `client_email`!'); }); }); // end describe('getGCSCredsFromEnv') - describe("CraftGCSClient class", () => { - describe("upload", () => { - it("calls the GCS library upload method with the right parameters", async () => { + describe('CraftGCSClient class', () => { + describe('upload', () => { + it('calls the GCS library upload method with the right parameters', async () => { expect.assertions(1); await client.uploadArtifact( @@ -174,11 +174,11 @@ describe("gcsApi module", () => { }); }); - it("removes leading slashes in upload destinations", async () => { + it('removes leading slashes in upload destinations', async () => { expect.assertions(1); await client.uploadArtifact(squirrelStatsLocalPath, { - path: "/" + squirrelStatsBucketPath.path, + path: '/' + squirrelStatsBucketPath.path, }); const { filename } = squirrelStatsArtifact; @@ -194,7 +194,7 @@ describe("gcsApi module", () => { }); }); - it("detects content type correctly for JS and map files", async () => { + it('detects content type correctly for JS and map files', async () => { expect.assertions(1); await client.uploadArtifact( @@ -206,13 +206,13 @@ describe("gcsApi module", () => { squirrelSimulatorLocalPath, expect.objectContaining({ metadata: expect.objectContaining({ - contentType: "application/javascript; charset=utf-8", + contentType: 'application/javascript; charset=utf-8', }), }) ); }); - it("allows overriding of default metadata", async () => { + it('allows overriding of default metadata', async () => { expect.assertions(1); await client.uploadArtifact( @@ -230,11 +230,11 @@ describe("gcsApi module", () => { ); }); - it("errors if GCS upload goes sideways", async () => { + it('errors if GCS upload goes sideways', async () => { expect.assertions(1); mockGCSUpload.mockImplementation(() => { - throw new Error("The squirrel got away!"); + throw new Error('The squirrel got away!'); }); const { filename } = squirrelSimulatorArtifact; @@ -252,7 +252,7 @@ describe("gcsApi module", () => { it("doesn't upload anything in dry run mode", async () => { expect.assertions(1); - process.env.DRY_RUN = "true"; + process.env.DRY_RUN = 'true'; await client.uploadArtifact( squirrelStatsLocalPath, @@ -263,8 +263,8 @@ describe("gcsApi module", () => { }); }); // end describe('upload') - describe("download", () => { - it("calls the GCS library download method with the right parameters", async () => { + describe('download', () => { + it('calls the GCS library download method with the right parameters', async () => { expect.assertions(1); await withTempDir(async (tempDownloadDirectory) => { @@ -290,17 +290,17 @@ describe("gcsApi module", () => { await expect( client.downloadArtifact( squirrelSimulatorArtifact.storedFile.downloadFilepath, - "./iDontExist/" + './iDontExist/' ) ).rejects.toThrowError(`directory does not exist!`); }); - it("errors if GCS download goes sideways", async () => { + it('errors if GCS download goes sideways', async () => { expect.assertions(1); await withTempDir(async (tempDownloadDirectory) => { mockGCSDownload.mockImplementation(() => { - throw new Error("The squirrel got away!"); + throw new Error('The squirrel got away!'); }); const { filename } = squirrelSimulatorArtifact; @@ -320,7 +320,7 @@ describe("gcsApi module", () => { await withTempDir(async (tempDownloadDirectory) => { expect.assertions(1); - process.env.DRY_RUN = "true"; + process.env.DRY_RUN = 'true'; await client.downloadArtifact( squirrelSimulatorArtifact.storedFile.downloadFilepath, @@ -332,8 +332,8 @@ describe("gcsApi module", () => { }); }); // end describe('download') - describe("listArtifactsForRevision", () => { - it("calls the GCS library getFiles method with the right parameters", async () => { + describe('listArtifactsForRevision', () => { + it('calls the GCS library getFiles method with the right parameters', async () => { expect.assertions(1); mockGCSGetFiles.mockReturnValue([[]]); @@ -353,7 +353,7 @@ describe("gcsApi module", () => { }); }); - it("converts GCSFile objects in response to RemoteArtifact objects", async () => { + it('converts GCSFile objects in response to RemoteArtifact objects', async () => { expect.assertions(1); mockGCSGetFiles.mockReturnValue([[squirrelStatsGCSFileObj]]); @@ -383,11 +383,11 @@ describe("gcsApi module", () => { expect(artifacts.length).toEqual(2); }); - it("errors if GCS file listing goes sideways", async () => { + it('errors if GCS file listing goes sideways', async () => { expect.assertions(1); mockGCSGetFiles.mockImplementation(() => { - throw new Error("The squirrel got away!"); + throw new Error('The squirrel got away!'); }); await expect( @@ -396,7 +396,7 @@ describe("gcsApi module", () => { squirrelRepo, squirrelSimulatorCommit ) - ).rejects.toThrowError("Error retrieving artifact list from GCS"); + ).rejects.toThrowError('Error retrieving artifact list from GCS'); }); }); // end describe('listArtifactsForRevision') }); // end describe('CraftGCSClient class') diff --git a/src/utils/__tests__/githubApi.test.ts b/src/utils/__tests__/githubApi.test.ts index 37a1547c..6277c8da 100644 --- a/src/utils/__tests__/githubApi.test.ts +++ b/src/utils/__tests__/githubApi.test.ts @@ -1,4 +1,4 @@ -import Github from "@octokit/rest"; +import Github from '@octokit/rest'; import { codeMatches, @@ -7,54 +7,54 @@ import { HTTP_RESPONSE_2XX, retryHttp, RetryParams, -} from "../githubApi"; +} from '../githubApi'; const mockRepos = { getContents: jest.fn(), }; // TODO rewrite with module mock, port github helpers from probot-release -jest.mock("@octokit/rest", () => +jest.mock('@octokit/rest', () => jest.fn().mockImplementation(() => ({ repos: mockRepos })) ); -describe("getFile", () => { +describe('getFile', () => { const github = new Github(); - const owner = "owner"; - const repo = "repo"; + const owner = 'owner'; + const repo = 'repo'; const getContents = (github.repos.getContents as unknown) as jest.Mock; - test("loads and decodes the file", async () => { + test('loads and decodes the file', async () => { expect.assertions(2); - const testContent = "test content."; + const testContent = 'test content.'; getContents.mockReturnValue({ - data: { content: Buffer.from(testContent).toString("base64") }, + data: { content: Buffer.from(testContent).toString('base64') }, }); const content = await getFile( github, owner, repo, - "/path/to/file", - "v1.0.0" + '/path/to/file', + 'v1.0.0' ); expect(getContents).toHaveBeenCalledWith({ - owner: "owner", - path: "/path/to/file", - ref: "v1.0.0", - repo: "repo", + owner: 'owner', + path: '/path/to/file', + ref: 'v1.0.0', + repo: 'repo', }); expect(content).toBe(testContent); }); - test("returns null for missing files", async () => { + test('returns null for missing files', async () => { expect.assertions(1); getContents.mockImplementation(() => { - const e = new Error("file not found") as any; + const e = new Error('file not found') as any; e.status = 404; throw e; }); @@ -63,16 +63,16 @@ describe("getFile", () => { github, owner, repo, - "/path/to/missing", - "v1.0.0" + '/path/to/missing', + 'v1.0.0' ); expect(content).toBe(undefined); }); - test("rejects all other errors", async () => { + test('rejects all other errors', async () => { expect.assertions(3); - const errorText = "internal server error"; + const errorText = 'internal server error'; getContents.mockImplementation(() => { const e = new Error(errorText) as any; e.status = 500; @@ -80,7 +80,7 @@ describe("getFile", () => { }); try { - await getFile(github, owner, repo, "/path/to/missing", "v1.0.0"); + await getFile(github, owner, repo, '/path/to/missing', 'v1.0.0'); } catch (e) { expect(e.message).toMatch(errorText); expect(e.status).toBe(500); @@ -89,25 +89,25 @@ describe("getFile", () => { }); }); -describe("codeMatches", () => { - test("accepts numerical code", () => { +describe('codeMatches', () => { + test('accepts numerical code', () => { expect(codeMatches(100, [100])).toBe(true); }); - test("accepts text code", () => { + test('accepts text code', () => { expect(codeMatches(101, [HTTP_RESPONSE_1XX])).toBe(true); }); - test("allows single value instead of a list", () => { + test('allows single value instead of a list', () => { expect(codeMatches(102, HTTP_RESPONSE_1XX)).toBe(true); }); - test("does not accept invalid code", () => { + test('does not accept invalid code', () => { expect(codeMatches(100, [200, HTTP_RESPONSE_2XX])).toBe(false); }); }); -describe("retryHttp", () => { +describe('retryHttp', () => { const params: Partial = { cooldown: 1 }; const errorCode = (c: number) => ({ status: c, @@ -115,14 +115,14 @@ describe("retryHttp", () => { // these are standing in for an async function (the type is () => // Promise) - const funcReturns = async () => Promise.resolve("result"); + const funcReturns = async () => Promise.resolve('result'); const funcThrows = async () => Promise.reject(errorCode(400)); - test("resolves without an error", async () => { - await expect(retryHttp(funcReturns, params)).resolves.toBe("result"); + test('resolves without an error', async () => { + await expect(retryHttp(funcReturns, params)).resolves.toBe('result'); }); - test("resolves after one retry", async () => { + test('resolves after one retry', async () => { const f = jest .fn() .mockImplementationOnce(funcThrows) @@ -130,10 +130,10 @@ describe("retryHttp", () => { expect( await retryHttp(f, { ...params, retryCodes: [400], retries: 1 }) - ).toBe("result"); + ).toBe('result'); }); - test("throws an error after max retries", async () => { + test('throws an error after max retries', async () => { expect.assertions(1); const f = jest .fn() @@ -143,13 +143,13 @@ describe("retryHttp", () => { try { await retryHttp(f, { ...params, retryCodes: [400], retries: 1 }); - throw Error("unreachable"); + throw Error('unreachable'); } catch (e) { return expect(e).toEqual(errorCode(400)); } }); - test("calls the cleanup function after each retry", async () => { + test('calls the cleanup function after each retry', async () => { const f = jest .fn() .mockImplementationOnce(funcThrows) @@ -167,11 +167,11 @@ describe("retryHttp", () => { retries: 2, retryCodes: [400], }) - ).toBe("result"); + ).toBe('result'); expect(cleanupCalled).toBe(2); }); - test("throws an error if error code is not in list", async () => { + test('throws an error if error code is not in list', async () => { expect.assertions(1); const f = jest .fn() @@ -180,7 +180,7 @@ describe("retryHttp", () => { try { await retryHttp(f, { ...params, retryCodes: [500] }); - throw Error("unreachable"); + throw Error('unreachable'); } catch (e) { return expect(e).toEqual(errorCode(400)); } diff --git a/src/utils/__tests__/helpers.test.ts b/src/utils/__tests__/helpers.test.ts index d29c2eb6..d7d18b79 100644 --- a/src/utils/__tests__/helpers.test.ts +++ b/src/utils/__tests__/helpers.test.ts @@ -1,6 +1,6 @@ -import { isDryRun } from "../helpers"; +import { isDryRun } from '../helpers'; -describe("isDryRun", () => { +describe('isDryRun', () => { /** * Helper function to test expected isDryRun() output given a DRY_RUN value * @@ -23,13 +23,13 @@ describe("isDryRun", () => { delete process.env.DRY_RUN; }); - test("undefined", () => testValue(undefined, false)); - test("empty string", () => testValue("", false)); - test("false", () => testValue("false", false)); - test("0", () => testValue("0", false)); - test("no", () => testValue("no", false)); - test("true", () => testValue("true", true)); - test("1", () => testValue("1", true)); - test("yes", () => testValue("yes", true)); - test("any non-empty string", () => testValue("dogs are great!", true)); + test('undefined', () => testValue(undefined, false)); + test('empty string', () => testValue('', false)); + test('false', () => testValue('false', false)); + test('0', () => testValue('0', false)); + test('no', () => testValue('no', false)); + test('true', () => testValue('true', true)); + test('1', () => testValue('1', true)); + test('yes', () => testValue('yes', true)); + test('any non-empty string', () => testValue('dogs are great!', true)); }); // end describe('isDryRun') diff --git a/src/utils/__tests__/noInput.test.ts b/src/utils/__tests__/noInput.test.ts index 738489ae..517135dc 100644 --- a/src/utils/__tests__/noInput.test.ts +++ b/src/utils/__tests__/noInput.test.ts @@ -1,48 +1,48 @@ /* eslint-env jest */ -import { hasInput, hasNoInput, resetNoInput, setNoInput } from "../noInput"; +import { hasInput, hasNoInput, resetNoInput, setNoInput } from '../noInput'; -describe("setNoInput", () => { +describe('setNoInput', () => { afterEach(() => { delete process.env.CI; delete process.env.CRAFT_NO_INPUT; resetNoInput(); }); - test("sets and returns true", () => { + test('sets and returns true', () => { setNoInput(true); expect(hasNoInput()).toBe(true); expect(hasInput()).toBe(false); }); - test("sets and returns false", () => { + test('sets and returns false', () => { setNoInput(false); expect(hasNoInput()).toBe(false); expect(hasInput()).toBe(true); }); }); -describe("resetNoInput", () => { +describe('resetNoInput', () => { afterEach(() => { delete process.env.CI; delete process.env.CRAFT_NO_INPUT; resetNoInput(); }); - test("sets noInput to false by default", () => { + test('sets noInput to false by default', () => { delete process.env.CRAFT_NO_INPUT; resetNoInput(); expect(hasNoInput()).toBe(false); }); - test("sets noInput to true via craft env", () => { - process.env.CRAFT_NO_INPUT = "1"; + test('sets noInput to true via craft env', () => { + process.env.CRAFT_NO_INPUT = '1'; resetNoInput(); expect(hasNoInput()).toBe(true); }); - test("sets noInput to true via CI env", () => { - process.env.CI = "1"; + test('sets noInput to true via CI env', () => { + process.env.CI = '1'; resetNoInput(); expect(hasNoInput()).toBe(true); }); diff --git a/src/utils/__tests__/objects.test.ts b/src/utils/__tests__/objects.test.ts index d3bde1b3..f3238561 100644 --- a/src/utils/__tests__/objects.test.ts +++ b/src/utils/__tests__/objects.test.ts @@ -1,8 +1,8 @@ -import { clearObjectProperties } from "../objects"; +import { clearObjectProperties } from '../objects'; -describe("clearObjectProperties", () => { - test("clears enumerable properties", () => { - const obj = { a: 1, test: "hello", f: () => 0, o: { 1: 2 } }; +describe('clearObjectProperties', () => { + test('clears enumerable properties', () => { + const obj = { a: 1, test: 'hello', f: () => 0, o: { 1: 2 } }; expect(clearObjectProperties(obj)).toEqual({}); expect(obj).toEqual({}); diff --git a/src/utils/__tests__/packagePath.test.ts b/src/utils/__tests__/packagePath.test.ts index e3400f9b..d06f702c 100644 --- a/src/utils/__tests__/packagePath.test.ts +++ b/src/utils/__tests__/packagePath.test.ts @@ -1,30 +1,30 @@ -import { parseCanonical } from "../packagePath"; +import { parseCanonical } from '../packagePath'; -describe("parseCanonical", () => { - test("parses valid cases properly", async () => { - expect(parseCanonical("pypi:sentry-sdk")).toEqual(["pypi", "sentry-sdk"]); - expect(parseCanonical("npm:@sentry/browser")).toEqual([ - "npm", - "@sentry", - "browser", +describe('parseCanonical', () => { + test('parses valid cases properly', async () => { + expect(parseCanonical('pypi:sentry-sdk')).toEqual(['pypi', 'sentry-sdk']); + expect(parseCanonical('npm:@sentry/browser')).toEqual([ + 'npm', + '@sentry', + 'browser', ]); - expect(parseCanonical("test-registry:a.1/b.2/c.3")).toEqual([ - "test-registry", - "a.1", - "b.2", - "c.3", + expect(parseCanonical('test-registry:a.1/b.2/c.3')).toEqual([ + 'test-registry', + 'a.1', + 'b.2', + 'c.3', ]); }); - test("allows colons as path separators", async () => { - expect(parseCanonical("maven:io.sentry:sentry")).toEqual([ - "maven", - "io.sentry", - "sentry", + test('allows colons as path separators', async () => { + expect(parseCanonical('maven:io.sentry:sentry')).toEqual([ + 'maven', + 'io.sentry', + 'sentry', ]); }); - test("throws an error for invalid canonical names", async () => { + test('throws an error for invalid canonical names', async () => { function expectRaisesError(name: string): void { try { parseCanonical(name); @@ -34,9 +34,9 @@ describe("parseCanonical", () => { } } - expectRaisesError("invalid"); - expectRaisesError("invalid:"); - expectRaisesError("a/b"); - expectRaisesError("registry:a/"); + expectRaisesError('invalid'); + expectRaisesError('invalid:'); + expectRaisesError('a/b'); + expectRaisesError('registry:a/'); }); }); diff --git a/src/utils/__tests__/strings.test.ts b/src/utils/__tests__/strings.test.ts index 326c91a5..717b8969 100644 --- a/src/utils/__tests__/strings.test.ts +++ b/src/utils/__tests__/strings.test.ts @@ -3,14 +3,14 @@ import { sanitizeObject, formatSize, formatJson, -} from "../strings"; +} from '../strings'; -describe("sanitizeObject", () => { - test("processes empty object", () => { +describe('sanitizeObject', () => { + test('processes empty object', () => { expect(sanitizeObject({})).toEqual({}); }); - test("throws an error if given non-object", () => { + test('throws an error if given non-object', () => { function expectRaisesError(value: any): void { try { sanitizeObject(value); @@ -20,77 +20,77 @@ describe("sanitizeObject", () => { } } expectRaisesError(123); - expectRaisesError("a"); + expectRaisesError('a'); expectRaisesError(null); }); - test("processes simple objects without changes", () => { + test('processes simple objects without changes', () => { expect(sanitizeObject({ 1: 2 })).toEqual({ 1: 2 }); }); - test("processes nested objects without changes", () => { - expect(sanitizeObject({ 1: { a: { 3: true } }, 2: "b" })).toEqual({ + test('processes nested objects without changes', () => { + expect(sanitizeObject({ 1: { a: { 3: true } }, 2: 'b' })).toEqual({ 1: { a: { 3: true } }, - 2: "b", + 2: 'b', }); }); - test("ignores function values", () => { + test('ignores function values', () => { expect(sanitizeObject({ f: () => true })).toEqual({}); }); - test("replaces null with undefined", () => { + test('replaces null with undefined', () => { expect(sanitizeObject({ 1: null })).toEqual({ 1: undefined }); }); - test("normalizes keys with dots", () => { - expect(sanitizeObject({ "1.2.3": 3 })).toEqual({ - "1.2.3": 3, - "1__2__3": 3, + test('normalizes keys with dots', () => { + expect(sanitizeObject({ '1.2.3': 3 })).toEqual({ + '1.2.3': 3, + '1__2__3': 3, }); }); }); -describe("renderTemplateSafe", () => { - test("renders basic template", () => { - expect(renderTemplateSafe("x{{ var }}", { var: 123 })).toBe("x123"); +describe('renderTemplateSafe', () => { + test('renders basic template', () => { + expect(renderTemplateSafe('x{{ var }}', { var: 123 })).toBe('x123'); }); - test("renders nested values", () => { - expect(renderTemplateSafe("x{{ var.d }}", { var: { d: 123 } })).toBe( - "x123" + test('renders nested values', () => { + expect(renderTemplateSafe('x{{ var.d }}', { var: { d: 123 } })).toBe( + 'x123' ); }); - test("renders nested values with dotted keys", () => { - expect(renderTemplateSafe("x{{ var.d__1 }}", { var: { "d.1": 123 } })).toBe( - "x123" + test('renders nested values with dotted keys', () => { + expect(renderTemplateSafe('x{{ var.d__1 }}', { var: { 'd.1': 123 } })).toBe( + 'x123' ); }); - test("does not render globals", () => { - expect(renderTemplateSafe("{{ process }}", {})).toBe(""); + test('does not render globals', () => { + expect(renderTemplateSafe('{{ process }}', {})).toBe(''); }); }); -describe("formatSize", () => { - test("formats byte sizes", () => { - expect(formatSize(123)).toBe("123 B"); +describe('formatSize', () => { + test('formats byte sizes', () => { + expect(formatSize(123)).toBe('123 B'); }); - test("formats kilobyte sizes", () => { - expect(formatSize(125952)).toBe("123.0 kB"); + test('formats kilobyte sizes', () => { + expect(formatSize(125952)).toBe('123.0 kB'); }); - test("formats megabyte sizes", () => { - expect(formatSize(1289748)).toBe("1.23 MB"); + test('formats megabyte sizes', () => { + expect(formatSize(1289748)).toBe('1.23 MB'); }); }); -describe("formatJson", () => { - test("formats an integer", () => { - expect(formatJson(123)).toBe("123"); +describe('formatJson', () => { + test('formats an integer', () => { + expect(formatJson(123)).toBe('123'); }); - test("formats an object", () => { - expect(formatJson({ int: 123, str: "hello", array: [2, 3, 4] })).toBe( + test('formats an object', () => { + expect(formatJson({ int: 123, str: 'hello', array: [2, 3, 4] })).toBe( `{ "int": 123, "str": "hello", @@ -102,9 +102,9 @@ describe("formatJson", () => { }` ); }); - test("serializes an error", () => { - const errorStr = formatJson(Error("oops")); - expect(errorStr).toContain("Error: oops"); - expect(errorStr).toContain("at Object"); + test('serializes an error', () => { + const errorStr = formatJson(Error('oops')); + expect(errorStr).toContain('Error: oops'); + expect(errorStr).toContain('at Object'); }); }); diff --git a/src/utils/__tests__/system.test.ts b/src/utils/__tests__/system.test.ts index 6d4d796e..5588295b 100644 --- a/src/utils/__tests__/system.test.ts +++ b/src/utils/__tests__/system.test.ts @@ -1,7 +1,7 @@ -import * as fs from "fs"; +import * as fs from 'fs'; -import { logger } from "../../logger"; -import { withTempFile } from "../files"; +import { logger } from '../../logger'; +import { withTempFile } from '../files'; import { calculateChecksum, @@ -11,78 +11,78 @@ import { replaceEnvVariable, sleepAsync, spawnProcess, -} from "../system"; +} from '../system'; -jest.mock("../../logger"); +jest.mock('../../logger'); -describe("spawnProcess", () => { - test("resolves on success with standard output", async () => { +describe('spawnProcess', () => { + test('resolves on success with standard output', async () => { expect.assertions(1); const stdout = - (await spawnProcess(process.execPath, ["-p", '"test"'])) || ""; - expect(stdout.toString()).toBe("test\n"); + (await spawnProcess(process.execPath, ['-p', '"test"'])) || ''; + expect(stdout.toString()).toBe('test\n'); }); - test("rejects on non-zero exit code", async () => { + test('rejects on non-zero exit code', async () => { try { expect.assertions(2); - await spawnProcess("test", [""]); + await spawnProcess('test', ['']); } catch (e) { expect(e.code).toBe(1); expect(e.message).toMatch(/code 1/); } }); - test("rejects on error", async () => { + test('rejects on error', async () => { try { expect.assertions(1); - await spawnProcess("this_command_does_not_exist"); + await spawnProcess('this_command_does_not_exist'); } catch (e) { expect(e.message).toMatch(/ENOENT/); } }); - test("attaches args on error", async () => { + test('attaches args on error', async () => { try { expect.assertions(1); - await spawnProcess("test", ["x", "y"]); + await spawnProcess('test', ['x', 'y']); } catch (e) { - expect(e.args).toEqual(["x", "y"]); + expect(e.args).toEqual(['x', 'y']); } }); - test("attaches options on error", async () => { + test('attaches options on error', async () => { try { expect.assertions(1); - await spawnProcess("test", [], { cwd: "/tmp/" }); + await spawnProcess('test', [], { cwd: '/tmp/' }); } catch (e) { - expect(e.options.cwd).toEqual("/tmp/"); + expect(e.options.cwd).toEqual('/tmp/'); } }); - test("strips env from options on error", async () => { + test('strips env from options on error', async () => { try { expect.assertions(1); - await spawnProcess("test", [], { env: { x: "123", password: "456" } }); + await spawnProcess('test', [], { env: { x: '123', password: '456' } }); } catch (e) { expect(e.options.env).toBeUndefined(); } }); - test("does not write to output by default", async () => { + test('does not write to output by default', async () => { const mockedLogInfo = logger.info as jest.Mock; - await spawnProcess(process.execPath, ["-p", '"test-string"']); + await spawnProcess(process.execPath, ['-p', '"test-string"']); expect(mockedLogInfo).toHaveBeenCalledTimes(0); }); - test("writes to output if told so", async () => { + test('writes to output if told so', async () => { const mockedLogInfo = logger.info as jest.Mock; await spawnProcess( process.execPath, - ["-e", 'process.stdout.write("test-string")'], + ['-e', 'process.stdout.write("test-string")'], {}, { showStdout: true } ); @@ -92,8 +92,8 @@ describe("spawnProcess", () => { }); }); -describe("sleepAsync", () => { - test("sleeps for at least the given number of ms", async () => { +describe('sleepAsync', () => { + test('sleeps for at least the given number of ms', async () => { const sleepMs = 50; const timeStart = new Date().getTime(); await sleepAsync(sleepMs); @@ -104,86 +104,86 @@ describe("sleepAsync", () => { }); }); -describe("replaceEnvVariable", () => { - test("replaces a variable", async () => { - expect(replaceEnvVariable("${ENV_VAR}", { ENV_VAR: "123" })).toBe("123"); +describe('replaceEnvVariable', () => { + test('replaces a variable', async () => { + expect(replaceEnvVariable('${ENV_VAR}', { ENV_VAR: '123' })).toBe('123'); }); - test("does not replace a variable if there is no curly braces", async () => { - expect(replaceEnvVariable("$ENV_VAR", { ENV_VAR: "123" })).toBe("$ENV_VAR"); + test('does not replace a variable if there is no curly braces', async () => { + expect(replaceEnvVariable('$ENV_VAR', { ENV_VAR: '123' })).toBe('$ENV_VAR'); }); - test("replaces a non-existing environment variable with empty string", async () => { - expect(replaceEnvVariable("${ENV_VAR}", {})).toBe(""); + test('replaces a non-existing environment variable with empty string', async () => { + expect(replaceEnvVariable('${ENV_VAR}', {})).toBe(''); }); }); -describe("calculateChecksum", () => { - test("Default checksum on a basic file", async () => { +describe('calculateChecksum', () => { + test('Default checksum on a basic file', async () => { expect.assertions(1); await withTempFile(async (tmpFilePath) => { - fs.writeFileSync(tmpFilePath, "\n"); + fs.writeFileSync(tmpFilePath, '\n'); const checksum = await calculateChecksum(tmpFilePath); expect(checksum).toBe( - "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b" + '01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b' ); }); }); - test("Base64-formatted checksum on a basic file", async () => { + test('Base64-formatted checksum on a basic file', async () => { expect.assertions(1); await withTempFile(async (tmpFilePath) => { - fs.writeFileSync(tmpFilePath, "\n"); + fs.writeFileSync(tmpFilePath, '\n'); const checksum = await calculateChecksum(tmpFilePath, { format: HashOutputFormat.Base64, }); - expect(checksum).toBe("AbpHGcgLb+kRsJGnwFEktk7uzpZOCcBY74+YBdrKVGs="); + expect(checksum).toBe('AbpHGcgLb+kRsJGnwFEktk7uzpZOCcBY74+YBdrKVGs='); }); }); - test("Base64-formatted checksum with custom algorithm on a basic file", async () => { + test('Base64-formatted checksum with custom algorithm on a basic file', async () => { expect.assertions(1); await withTempFile(async (tmpFilePath) => { - fs.writeFileSync(tmpFilePath, "\n"); + fs.writeFileSync(tmpFilePath, '\n'); const checksum = await calculateChecksum(tmpFilePath, { algorithm: HashAlgorithm.SHA384, format: HashOutputFormat.Base64, }); expect(checksum).toBe( - "7GZOiJ7WwbJ2PKz3iZ2Vt/NHNz65guUjQZ/uo6o2LYkbO/Al8pImelhUBJCReJw+" + '7GZOiJ7WwbJ2PKz3iZ2Vt/NHNz65guUjQZ/uo6o2LYkbO/Al8pImelhUBJCReJw+' ); }); }); }); -describe("isExecutableInPath", () => { - test("checks for existing executable", () => { - expect(hasExecutable("node")).toBe(true); +describe('isExecutableInPath', () => { + test('checks for existing executable', () => { + expect(hasExecutable('node')).toBe(true); }); - test("checks for non-existing executable", () => { - expect(hasExecutable("not-existing-executable")).toBe(false); + test('checks for non-existing executable', () => { + expect(hasExecutable('not-existing-executable')).toBe(false); }); - test("checks for existing executable using absolute path", () => { + test('checks for existing executable using absolute path', () => { expect(hasExecutable(`${process.cwd()}/node_modules/.bin/jest`)).toBe(true); }); - test("checks for non-existing executable using absolute path", () => { - expect(hasExecutable("/dev/null/non-existing-binary")).toBe(false); + test('checks for non-existing executable using absolute path', () => { + expect(hasExecutable('/dev/null/non-existing-binary')).toBe(false); }); - test("checks for existing executable using relative path", () => { - expect(hasExecutable("./node_modules/.bin/jest")).toBe(true); + test('checks for existing executable using relative path', () => { + expect(hasExecutable('./node_modules/.bin/jest')).toBe(true); }); - test("checks for non-existing executable using relative path", () => { - expect(hasExecutable("./bin/non-existing-binary")).toBe(false); + test('checks for non-existing executable using relative path', () => { + expect(hasExecutable('./bin/non-existing-binary')).toBe(false); }); }); diff --git a/src/utils/__tests__/version.test.ts b/src/utils/__tests__/version.test.ts index 5e63b49a..ef0275f5 100644 --- a/src/utils/__tests__/version.test.ts +++ b/src/utils/__tests__/version.test.ts @@ -8,47 +8,47 @@ import { parseVersion, SemVer, versionGreaterOrEqualThan, -} from "../version"; +} from '../version'; -describe("getVersion", () => { - test("extracts a basic SemVer versions", () => { - expect(getVersion("1.0.0")).toBe("1.0.0"); +describe('getVersion', () => { + test('extracts a basic SemVer versions', () => { + expect(getVersion('1.0.0')).toBe('1.0.0'); }); test('extracts a SemVer version with leading "v"', () => { - expect(getVersion("v1.0.0")).toBe("1.0.0"); + expect(getVersion('v1.0.0')).toBe('1.0.0'); }); - test("extracts a SemVer version from text", () => { - expect(getVersion("1.0.0 (foobar)")).toBe("1.0.0"); + test('extracts a SemVer version from text', () => { + expect(getVersion('1.0.0 (foobar)')).toBe('1.0.0'); }); - test("extracts a SemVer, but ignores subpatch level", () => { - expect(getVersion("1.0.0.1")).toBe("1.0.0"); + test('extracts a SemVer, but ignores subpatch level', () => { + expect(getVersion('1.0.0.1')).toBe('1.0.0'); }); }); -describe("isValidVersion", () => { - test("accepts valid version", () => { - expect(isValidVersion("1.2.3")).toBe(true); +describe('isValidVersion', () => { + test('accepts valid version', () => { + expect(isValidVersion('1.2.3')).toBe(true); }); - test("accepts valid pre-release version", () => { - expect(isValidVersion("1.2.3-beta")).toBe(true); + test('accepts valid pre-release version', () => { + expect(isValidVersion('1.2.3-beta')).toBe(true); }); - test("accepts valid Python-style version", () => { - expect(isValidVersion("1.2.3rc1")).toBe(true); + test('accepts valid Python-style version', () => { + expect(isValidVersion('1.2.3rc1')).toBe(true); }); test('does not accept leading "v"', () => { - expect(isValidVersion("v1.2.3")).toBe(false); + expect(isValidVersion('v1.2.3')).toBe(false); }); }); -describe("parseVersion", () => { - test("parses a full SemVer version", () => { - expect(parseVersion("1.2.3")).toEqual({ +describe('parseVersion', () => { + test('parses a full SemVer version', () => { + expect(parseVersion('1.2.3')).toEqual({ major: 1, minor: 2, patch: 3, @@ -56,87 +56,87 @@ describe("parseVersion", () => { }); test('parses a SemVer with leading "v"', () => { - expect(parseVersion("v1.2.3")).toEqual({ + expect(parseVersion('v1.2.3')).toEqual({ major: 1, minor: 2, patch: 3, }); }); - test("parses a pre-release SemVer", () => { - expect(parseVersion("v1.2.3-beta")).toEqual({ + test('parses a pre-release SemVer', () => { + expect(parseVersion('v1.2.3-beta')).toEqual({ major: 1, minor: 2, patch: 3, - pre: "beta", + pre: 'beta', }); }); - test("parses a complicated pre-release SemVer", () => { - expect(parseVersion("v1.2.3-beta.1")).toEqual({ + test('parses a complicated pre-release SemVer', () => { + expect(parseVersion('v1.2.3-beta.1')).toEqual({ major: 1, minor: 2, patch: 3, - pre: "beta.1", + pre: 'beta.1', }); }); - test("parses a SemVer with build metadata", () => { - expect(parseVersion("v1.2.3+linux")).toEqual({ - build: "linux", + test('parses a SemVer with build metadata', () => { + expect(parseVersion('v1.2.3+linux')).toEqual({ + build: 'linux', major: 1, minor: 2, patch: 3, }); }); - test("parses a pre-release SemVer with build metadata", () => { - expect(parseVersion("v1.2.3-beta+linux")).toEqual({ - build: "linux", + test('parses a pre-release SemVer with build metadata', () => { + expect(parseVersion('v1.2.3-beta+linux')).toEqual({ + build: 'linux', major: 1, minor: 2, patch: 3, - pre: "beta", + pre: 'beta', }); }); - test("parses a Python-style version", () => { - expect(parseVersion("v11.22.33rc1")).toEqual({ + test('parses a Python-style version', () => { + expect(parseVersion('v11.22.33rc1')).toEqual({ major: 11, minor: 22, patch: 33, - pre: "rc1", + pre: 'rc1', }); }); - test("does not parse an invalid version", () => { - expect(parseVersion("v1.2")).toBeNull(); + test('does not parse an invalid version', () => { + expect(parseVersion('v1.2')).toBeNull(); }); - test("cannot parse empty value", () => { - expect(parseVersion("")).toBeNull(); + test('cannot parse empty value', () => { + expect(parseVersion('')).toBeNull(); }); }); -describe("isPreviewRelease", () => { - test("accepts semver preview release", () => { - expect(isPreviewRelease("2.3.4-preview1")).toBe(true); +describe('isPreviewRelease', () => { + test('accepts semver preview release', () => { + expect(isPreviewRelease('2.3.4-preview1')).toBe(true); }); - test("accepts Python-style preview release", () => { - expect(isPreviewRelease("2.3.4rc0")).toBe(true); + test('accepts Python-style preview release', () => { + expect(isPreviewRelease('2.3.4rc0')).toBe(true); }); - test("does not accept non-preview release", () => { - expect(isPreviewRelease("2.3.4")).toBe(false); + test('does not accept non-preview release', () => { + expect(isPreviewRelease('2.3.4')).toBe(false); }); - test("does not accept non-release strings", () => { - expect(isPreviewRelease("4-preview")).toBe(false); + test('does not accept non-release strings', () => { + expect(isPreviewRelease('4-preview')).toBe(false); }); }); -describe("versionGreaterOrEqualThan", () => { +describe('versionGreaterOrEqualThan', () => { function semVerFactory( major: number, minor: number, @@ -147,57 +147,57 @@ describe("versionGreaterOrEqualThan", () => { return { major, minor, patch, pre, build }; } - test("compares different patch versions", () => { + test('compares different patch versions', () => { const v1 = semVerFactory(1, 2, 3); const v2 = semVerFactory(1, 2, 2); expect(versionGreaterOrEqualThan(v1, v2)).toBe(true); expect(versionGreaterOrEqualThan(v2, v1)).toBe(false); }); - test("compares different major versions", () => { + test('compares different major versions', () => { const v1 = semVerFactory(2, 0, 0); const v2 = semVerFactory(3, 0, 0); expect(versionGreaterOrEqualThan(v1, v2)).toBe(false); expect(versionGreaterOrEqualThan(v2, v1)).toBe(true); }); - test("compares different major versions", () => { + test('compares different major versions', () => { const v1 = semVerFactory(3, 1, 0); const v2 = semVerFactory(3, 0, 1); expect(versionGreaterOrEqualThan(v1, v2)).toBe(true); expect(versionGreaterOrEqualThan(v2, v1)).toBe(false); }); - test("equals true for equal versions", () => { + test('equals true for equal versions', () => { const v1 = semVerFactory(0, 1, 2); const v2 = semVerFactory(0, 1, 2); expect(versionGreaterOrEqualThan(v1, v2)).toBe(true); }); - test("prefers versions with pre-release parts", () => { - const v1 = semVerFactory(0, 1, 2, "rc0"); + test('prefers versions with pre-release parts', () => { + const v1 = semVerFactory(0, 1, 2, 'rc0'); const v2 = semVerFactory(0, 1, 2); expect(versionGreaterOrEqualThan(v1, v2)).toBe(false); expect(versionGreaterOrEqualThan(v2, v1)).toBe(true); }); - test("throws an exception if there are build parts", () => { - const v1 = semVerFactory(0, 1, 2, undefined, "build123"); + test('throws an exception if there are build parts', () => { + const v1 = semVerFactory(0, 1, 2, undefined, 'build123'); const v2 = semVerFactory(0, 1, 2); expect(() => versionGreaterOrEqualThan(v1, v2)).toThrowError(); expect(() => versionGreaterOrEqualThan(v2, v1)).toThrowError(); }); }); -describe("getPackage", () => { - test("reads package.json", () => { +describe('getPackage', () => { + test('reads package.json', () => { const pkg = getPackage(); - expect(pkg.name).toBe("@sentry/craft"); + expect(pkg.name).toBe('@sentry/craft'); }); }); -describe("getPackageVersion", () => { - test("reads package.json", () => { +describe('getPackageVersion', () => { + test('reads package.json', () => { const version = getPackage().version; expect(isValidVersion(version)).toBe(true); }); diff --git a/src/utils/async.ts b/src/utils/async.ts index f347b445..1624e5a2 100644 --- a/src/utils/async.ts +++ b/src/utils/async.ts @@ -1,5 +1,5 @@ -import * as _ from "lodash"; -import { reportError } from "./errors"; +import * as _ from 'lodash'; +import { reportError } from './errors'; /** * Asynchronously calls the predicate on every element of the array and filters diff --git a/src/utils/awsLambdaLayerManager.ts b/src/utils/awsLambdaLayerManager.ts index 52ede14e..d99324d8 100644 --- a/src/utils/awsLambdaLayerManager.ts +++ b/src/utils/awsLambdaLayerManager.ts @@ -1,13 +1,13 @@ -import { DescribeRegionsCommandOutput, EC2 } from "@aws-sdk/client-ec2"; -import { Lambda } from "@aws-sdk/client-lambda"; -import { logger as loggerRaw } from "../logger"; +import { DescribeRegionsCommandOutput, EC2 } from '@aws-sdk/client-ec2'; +import { Lambda } from '@aws-sdk/client-lambda'; +import { logger as loggerRaw } from '../logger'; -const logger = loggerRaw.withScope("[aws-lambda-layer]"); +const logger = loggerRaw.withScope('[aws-lambda-layer]'); /** Prefix of the canonical name. */ -const RUNTIME_CANONICAL_PREFIX = "aws-layer:"; +const RUNTIME_CANONICAL_PREFIX = 'aws-layer:'; /** Substring used to separate the different ARN parts. */ -const ARN_SEPARATOR = ":"; +const ARN_SEPARATOR = ':'; /** Index (0-based) of the account number in the ARN. */ const ARN_ACCOUNT_INDEX = 4; @@ -79,9 +79,9 @@ export class AwsLambdaLayerManager { await lambda.addLayerVersionPermission({ LayerName: this.layerName, VersionNumber: publishedLayer.Version, - StatementId: "public", - Action: "lambda:GetLayerVersion", - Principal: "*", + StatementId: 'public', + Action: 'lambda:GetLayerVersion', + Principal: '*', }); if (this.verboseInfo) { @@ -91,7 +91,7 @@ export class AwsLambdaLayerManager { return { region: region, - arn: publishedLayer.LayerVersionArn || "", + arn: publishedLayer.LayerVersionArn || '', version: publishedLayer.Version || -1, }; } @@ -108,7 +108,7 @@ export class AwsLambdaLayerManager { return await this.publishLayerToRegion(region); } catch (error) { logger.warn( - "Something went wrong with AWS trying to publish to region " + + 'Something went wrong with AWS trying to publish to region ' + `${region}: ${error.message}` ); return undefined; @@ -136,12 +136,12 @@ export class AwsLambdaLayerManager { * https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/EC2.html#describeRegions-property */ export async function getRegionsFromAws(): Promise { - logger.debug("Fetching AWS regions..."); - const ec2 = new EC2({ region: "us-east-2" }); + logger.debug('Fetching AWS regions...'); + const ec2 = new EC2({ region: 'us-east-2' }); try { return await ec2.describeRegions({}); } catch (error) { - throw new Error("AWS error fetching regions."); + throw new Error('AWS error fetching regions.'); } } diff --git a/src/utils/changes.ts b/src/utils/changes.ts index b247f862..bb52cc1c 100644 --- a/src/utils/changes.ts +++ b/src/utils/changes.ts @@ -1,11 +1,11 @@ -import { getVersion } from "./version"; +import { getVersion } from './version'; /** * Path to the changelog file in the target repository */ -export const DEFAULT_CHANGELOG_PATH = "CHANGELOG.md"; -export const DEFAULT_UNRELEASED_TITLE = "Unreleased"; -const DEFAULT_CHANGESET_BODY = "- No documented changes."; +export const DEFAULT_CHANGELOG_PATH = 'CHANGELOG.md'; +export const DEFAULT_UNRELEASED_TITLE = 'Unreleased'; +const DEFAULT_CHANGESET_BODY = '- No documented changes.'; /** * A single changeset with name and description @@ -42,7 +42,7 @@ function extractChangeset(markdown: string, location: ChangesetLoc): Changeset { const end = location.end ? location.end.index : undefined; const body = markdown.substring(start, end).trim(); const name = (location.start[2] || location.start[3]) - .replace(/\(.*\)$/, "") + .replace(/\(.*\)$/, '') .trim(); return { name, body }; } @@ -155,11 +155,11 @@ export function prependChangeset( // Try to locate the top-most non-empty header, no matter what is inside const start = locateChangeset(markdown, Boolean)?.start; const padding = start?.[1]?.length || 0; - const padStr = new Array(padding + 1).join(" "); + const padStr = new Array(padding + 1).join(' '); const body = changeset.body || `${padStr}${DEFAULT_CHANGESET_BODY}`; let header; if (start?.[3]) { - const underline = new Array(changeset.name.length + 1).join("-"); + const underline = new Array(changeset.name.length + 1).join('-'); header = `${changeset.name}\n${underline}`; } else { header = `## ${changeset.name}`; diff --git a/src/utils/checksum.ts b/src/utils/checksum.ts index 067b500a..5e7229f3 100644 --- a/src/utils/checksum.ts +++ b/src/utils/checksum.ts @@ -1,9 +1,9 @@ import { BaseArtifactProvider, RemoteArtifact, -} from "../artifact_providers/base"; -import { ConfigurationError } from "./errors"; -import { HashAlgorithm, HashOutputFormat } from "./system"; +} from '../artifact_providers/base'; +import { ConfigurationError } from './errors'; +import { HashAlgorithm, HashOutputFormat } from './system'; /** Describes a checksum entry. */ export interface ChecksumEntry { @@ -31,7 +31,7 @@ export function castChecksums(checksums: any[]): ChecksumEntry[] { } return checksums.map( (item: any): ChecksumEntry => { - if (typeof item !== "object" || !item.algorithm || !item.format) { + if (typeof item !== 'object' || !item.algorithm || !item.format) { throw new ConfigurationError( `Invalid checksum type: ${JSON.stringify(item)}` ); diff --git a/src/utils/env.ts b/src/utils/env.ts index 7185a6a5..bd3151c2 100644 --- a/src/utils/env.ts +++ b/src/utils/env.ts @@ -1,15 +1,15 @@ -import { existsSync, statSync } from "fs"; -import { join } from "path"; -const os = require("os"); +import { existsSync, statSync } from 'fs'; +import { join } from 'path'; +const os = require('os'); -import nvar from "nvar"; +import nvar from 'nvar'; -import { CONFIG_FILE_NAME, getConfigFileDir } from "../config"; -import { ConfigurationError } from "./errors"; -import { logger } from "../logger"; +import { CONFIG_FILE_NAME, getConfigFileDir } from '../config'; +import { ConfigurationError } from './errors'; +import { logger } from '../logger'; /** File name where additional environment variables are stored */ -export const ENV_FILE_NAME = ".craft.env"; +export const ENV_FILE_NAME = '.craft.env'; /** * A token, key, or other value which can be stored either in an env file or @@ -169,7 +169,7 @@ export function readEnvironmentConfig(overwriteExisting = false): void { * only one is required. */ export function checkEnvForPrerequisite(...varList: RequiredConfigVar[]): void { - const varNames = varList.map((v) => v.name).join(" or "); + const varNames = varList.map((v) => v.name).join(' or '); logger.debug(`Checking for environment variable(s) ${varNames}`); if (!varList.some(envHasVar)) { diff --git a/src/utils/errors.ts b/src/utils/errors.ts index 676217ac..c5e2a59a 100644 --- a/src/utils/errors.ts +++ b/src/utils/errors.ts @@ -1,6 +1,6 @@ -import { logger } from "../logger"; -import { isDryRun } from "./helpers"; -import { captureException } from "@sentry/node"; +import { logger } from '../logger'; +import { isDryRun } from './helpers'; +import { captureException } from '@sentry/node'; /** * Custom error class that describes client configuration errors @@ -39,7 +39,7 @@ export function reportError( throw errorObj; } else { // conversely, convert the error to a string if it isn't already one - const errorStr = typeof error === "string" ? error : String(error); + const errorStr = typeof error === 'string' ? error : String(error); errorLogger.error(`[dry-run] ${errorStr}`); } } @@ -56,14 +56,14 @@ export function reportError( export function coerceType( obj: T, typeName: - | "string" - | "number" - | "bigint" - | "boolean" - | "symbol" - | "undefined" - | "object" - | "function", + | 'string' + | 'number' + | 'bigint' + | 'boolean' + | 'symbol' + | 'undefined' + | 'object' + | 'function', message?: string ): T | never { const objType = typeof obj; diff --git a/src/utils/files.ts b/src/utils/files.ts index 3b13f1ba..49cd36b1 100644 --- a/src/utils/files.ts +++ b/src/utils/files.ts @@ -1,11 +1,11 @@ -import * as fs from "fs"; -import * as os from "os"; -import * as path from "path"; -import rimraf from "rimraf"; -import * as tmp from "tmp"; -import * as util from "util"; +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; +import rimraf from 'rimraf'; +import * as tmp from 'tmp'; +import * as util from 'util'; -import { filterAsync } from "./async"; +import { filterAsync } from './async'; const lstat = util.promisify(fs.lstat); const readdirp = util.promisify(fs.readdir); @@ -75,7 +75,7 @@ export async function listFiles(directory: string): Promise { export async function withTempDir( callback: (arg: string) => T | Promise, cleanup = true, - prefix = "craft-" + prefix = 'craft-' ): Promise { const directory = await mkdtemp(path.join(os.tmpdir(), prefix)); try { @@ -108,7 +108,7 @@ export async function withTempDir( export async function withTempFile( callback: (arg: string) => T | Promise, cleanup = true, - prefix = "craft-" + prefix = 'craft-' ): Promise { tmp.setGracefulCleanup(); const tmpFile = tmp.fileSync({ prefix }); @@ -130,8 +130,8 @@ export async function withTempFile( */ export function detectContentType(artifactName: string): string | undefined { const extensionToType: Array<[RegExp, string]> = [ - [/\.js$/, "application/javascript; charset=utf-8"], - [/\.js\.map$/, "application/json; charset=utf-8"], + [/\.js$/, 'application/javascript; charset=utf-8'], + [/\.js\.map$/, 'application/json; charset=utf-8'], ]; for (const entry of extensionToType) { const [regex, contentType] = entry; diff --git a/src/utils/filters.ts b/src/utils/filters.ts index ed51f825..72dc9d0b 100644 --- a/src/utils/filters.ts +++ b/src/utils/filters.ts @@ -15,8 +15,8 @@ * @returns Regular expression object that was created from the string */ export function stringToRegexp(str: string): RegExp { - const firstSlash = str.indexOf("/"); - const lastSlash = str.lastIndexOf("/"); + const firstSlash = str.indexOf('/'); + const lastSlash = str.lastIndexOf('/'); if (firstSlash !== 0 || lastSlash < 2) { throw new TypeError(`Invalid RegExp string specified: ${str}`); } diff --git a/src/utils/gcsApi.ts b/src/utils/gcsApi.ts index fe79bd24..8c95a756 100644 --- a/src/utils/gcsApi.ts +++ b/src/utils/gcsApi.ts @@ -1,20 +1,20 @@ -import * as fs from "fs"; -import * as path from "path"; +import * as fs from 'fs'; +import * as path from 'path'; import { Bucket as GCSBucket, File as GCSFile, Storage as GCSStorage, UploadOptions as GCSUploadOptions, -} from "@google-cloud/storage"; -import { isDryRun } from "./helpers"; +} from '@google-cloud/storage'; +import { isDryRun } from './helpers'; -import { logger, Logger, logger as loggerRaw } from "../logger"; -import { reportError, ConfigurationError } from "./errors"; -import { checkEnvForPrerequisite, RequiredConfigVar } from "./env"; -import { detectContentType } from "./files"; -import { RemoteArtifact } from "../artifact_providers/base"; -import { formatJson } from "./strings"; +import { logger, Logger, logger as loggerRaw } from '../logger'; +import { reportError, ConfigurationError } from './errors'; +import { checkEnvForPrerequisite, RequiredConfigVar } from './env'; +import { detectContentType } from './files'; +import { RemoteArtifact } from '../artifact_providers/base'; +import { formatJson } from './strings'; const DEFAULT_MAX_RETRIES = 5; export const DEFAULT_UPLOAD_METADATA = { cacheControl: `public, max-age=300` }; @@ -121,7 +121,7 @@ export function getGCSCredsFromEnv( reportError(`Error parsing JSON credentials: ${err}`); } - for (const field of ["project_id", "client_email", "private_key"]) { + for (const field of ['project_id', 'client_email', 'private_key']) { if (!parsedCofig[field]) { reportError(`GCS credentials missing \`${field}\`!`); } @@ -181,7 +181,7 @@ export class CraftGCSClient { // stopped normalizing paths. If you keep this, you'll end up with a path // like `//your/dir/and/file` instead of `/your/dir/and/file` // See #169 for more information. - if (pathInBucket[0] === "/") { + if (pathInBucket[0] === '/') { pathInBucket = pathInBucket.substring(1); } @@ -243,7 +243,7 @@ export class CraftGCSClient { this.logger.debug( `Successfully uploaded \`${filename}\`. It can be downloaded by running ` + `\`gsutil cp ${path.posix.join( - "gs://", + 'gs://', this.bucketName, pathInBucket, filename diff --git a/src/utils/githubApi.ts b/src/utils/githubApi.ts index 759e816d..349b2012 100644 --- a/src/utils/githubApi.ts +++ b/src/utils/githubApi.ts @@ -1,12 +1,12 @@ -import Github from "@octokit/rest"; -import request from "request"; -import { Duplex, Readable } from "stream"; +import Github from '@octokit/rest'; +import request from 'request'; +import { Duplex, Readable } from 'stream'; -import { LOG_LEVEL, logger } from "../logger"; +import { LOG_LEVEL, logger } from '../logger'; -import { ConfigurationError } from "./errors"; -import { isDryRun } from "./helpers"; -import { sleepAsync } from "./system"; +import { ConfigurationError } from './errors'; +import { isDryRun } from './helpers'; +import { sleepAsync } from './system'; export const HTTP_UNPROCESSABLE_ENTITY = 422; export const HTTP_RESPONSE_1XX = /^1\d\d$/; @@ -53,9 +53,9 @@ export class GithubRemote { /** GitHub personal authentication token */ protected apiToken?: string; /** GitHub hostname */ - protected readonly GITHUB_HOSTNAME: string = "github.com"; + protected readonly GITHUB_HOSTNAME: string = 'github.com'; /** Protocol prefix */ - protected readonly PROTOCOL_PREFIX: string = "https://"; + protected readonly PROTOCOL_PREFIX: string = 'https://'; /** Url in the form of /OWNER/REPO/ */ protected readonly url: string; @@ -102,7 +102,7 @@ export class GithubRemote { const authData = this.username && this.apiToken ? `${this.username}:${this.apiToken}@` - : ""; + : ''; return this.PROTOCOL_PREFIX + authData + this.GITHUB_HOSTNAME + this.url; } } @@ -117,7 +117,7 @@ export function getGithubApiToken(): string { process.env.GITHUB_TOKEN || process.env.GITHUB_API_TOKEN; if (!githubApiToken) { throw new ConfigurationError( - "GitHub target: GITHUB_TOKEN not found in the environment" + 'GitHub target: GITHUB_TOKEN not found in the environment' ); } return githubApiToken; @@ -131,7 +131,7 @@ export function getGithubApiToken(): string { * @param token Github authentication token * @returns Github client */ -export function getGithubClient(token = ""): Github { +export function getGithubClient(token = ''): Github { const githubApiToken = token || getGithubApiToken(); const attrs = { @@ -147,7 +147,7 @@ export function getGithubClient(token = ""): Github { } // eslint-disable-next-line @typescript-eslint/no-var-requires - const { retry } = require("@octokit/plugin-retry"); + const { retry } = require('@octokit/plugin-retry'); const octokitWithRetries = Github.plugin(retry); return new octokitWithRetries(attrs); } @@ -162,7 +162,7 @@ export async function getAuthUsername(github: Github): Promise { const userData = await github.users.getAuthenticated({}); const username = (userData.data || {}).login; if (!username) { - throw new Error("Cannot reliably detect Github username, aborting"); + throw new Error('Cannot reliably detect Github username, aborting'); } return username; } @@ -195,7 +195,7 @@ export async function getFile( if (response.data instanceof Array || response.data.content === undefined) { return undefined; } - return Buffer.from(response.data.content, "base64").toString(); + return Buffer.from(response.data.content, 'base64').toString(); } catch (e) { if (e.status === 404) { return undefined; @@ -240,14 +240,14 @@ export async function mergeReleaseBranch( ): Promise { const baseBranch = base || (await getDefaultBranch(github, owner, repo)); if (!baseBranch) { - throw new Error("Cannot determine base branch while merging"); + throw new Error('Cannot determine base branch while merging'); } try { logger.info(`Merging release branch: "${branch}" into "${baseBranch}"...`); if (isDryRun()) { - logger.info("[dry-run] Skipping merge."); + logger.info('[dry-run] Skipping merge.'); return undefined; } @@ -261,7 +261,7 @@ export async function mergeReleaseBranch( logger.info(`Merging: done.`); return response.data.sha; } else if (response.status === 204) { - logger.warn("Base already contains the head, nothing to merge"); + logger.warn('Base already contains the head, nothing to merge'); return undefined; } else { throw new Error(`Unexpected response: ${JSON.stringify(response)}`); @@ -271,7 +271,7 @@ export async function mergeReleaseBranch( // Conflicts found logger.error( `Cannot merge release branch "${branch}": conflicts detected`, - "Please resolve the conflicts and merge the branch manually:", + 'Please resolve the conflicts and merge the branch manually:', ` git checkout master && git merge ${branch}` ); } @@ -334,7 +334,7 @@ export function codeMatches( } for (const pattern of patternList) { - if (typeof pattern === "number") { + if (typeof pattern === 'number') { if (pattern === code) { return true; } diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index 3e47400b..068debb9 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -7,6 +7,6 @@ export function isDryRun(): boolean { const dryRun = process.env.DRY_RUN; return ( - Boolean(dryRun) && dryRun !== "false" && dryRun !== "0" && dryRun !== "no" + Boolean(dryRun) && dryRun !== 'false' && dryRun !== '0' && dryRun !== 'no' ); } diff --git a/src/utils/noInput.ts b/src/utils/noInput.ts index 506e393d..3ff6dae7 100644 --- a/src/utils/noInput.ts +++ b/src/utils/noInput.ts @@ -33,7 +33,7 @@ export function setNoInput(val: boolean): void { * a true-ish value. */ export function resetNoInput(): void { - const envVal = process.env.CRAFT_NO_INPUT || process.env.CI || ""; + const envVal = process.env.CRAFT_NO_INPUT || process.env.CI || ''; noInput = - envVal === "0" || envVal.toLowerCase() === "false" ? false : !!envVal; + envVal === '0' || envVal.toLowerCase() === 'false' ? false : !!envVal; } diff --git a/src/utils/packagePath.ts b/src/utils/packagePath.ts index ee7bee57..cfadb83d 100644 --- a/src/utils/packagePath.ts +++ b/src/utils/packagePath.ts @@ -1,6 +1,6 @@ -import * as path from "path"; -import { RegistryPackageType } from "../targets/registry"; -import { ConfigurationError } from "./errors"; +import * as path from 'path'; +import { RegistryPackageType } from '../targets/registry'; +import { ConfigurationError } from './errors'; /** * Returns the path to the SDK, given its canonical name. @@ -11,7 +11,7 @@ import { ConfigurationError } from "./errors"; */ function getSdkPackagePath(registryDir: string, canonical: string): string { const packageDirs = parseCanonical(canonical); - return path.posix.join(registryDir, "packages", ...packageDirs); + return path.posix.join(registryDir, 'packages', ...packageDirs); } /** @@ -23,12 +23,12 @@ function getSdkPackagePath(registryDir: string, canonical: string): string { */ function getAppPackagePath(registryDir: string, canonical: string): string { const packageDirs = parseCanonical(canonical); - if (packageDirs[0] !== "app") { + if (packageDirs[0] !== 'app') { throw new ConfigurationError( `Invalid canonical entry for an app: ${canonical}` ); } - return path.posix.join(registryDir, "apps", ...packageDirs.slice(1)); + return path.posix.join(registryDir, 'apps', ...packageDirs.slice(1)); } /** @@ -67,18 +67,18 @@ export function getPackageDirPath( * @returns A list of directories */ export function parseCanonical(canonicalName: string): string[] { - const [registry, ...splitPackageName] = canonicalName.split(":"); + const [registry, ...splitPackageName] = canonicalName.split(':'); // This essentially replaces colons with forward slashes for the package name // of the initial canonical name - const packageName = splitPackageName.join("/"); + const packageName = splitPackageName.join('/'); if (!registry || !packageName) { throw new ConfigurationError( `Cannot parse canonical name for the package: ${canonicalName}` ); } - const packageDirs = packageName.split("/"); + const packageDirs = packageName.split('/'); if (packageDirs.some((x) => !x)) { throw new ConfigurationError( `Cannot parse canonical name for the package: ${canonicalName}` diff --git a/src/utils/registry.ts b/src/utils/registry.ts index e74e2581..d1032dec 100644 --- a/src/utils/registry.ts +++ b/src/utils/registry.ts @@ -1,10 +1,10 @@ -import * as fs from "fs"; -import * as path from "path"; +import * as fs from 'fs'; +import * as path from 'path'; -import { logger } from "../logger"; -import { createSymlinks } from "./symlink"; -import { reportError } from "./errors"; -import { GithubRemote } from "./githubApi"; +import { logger } from '../logger'; +import { createSymlinks } from './symlink'; +import { reportError } from './errors'; +import { GithubRemote } from './githubApi'; /** * Gets the package manifest version in the given directory. @@ -20,7 +20,7 @@ export async function getPackageManifest( if (fs.existsSync(versionFilePath)) { reportError(`Version file for "${version}" already exists. Aborting.`); } - const packageManifestPath = path.join(packageDirPath, "latest.json"); + const packageManifestPath = path.join(packageDirPath, 'latest.json'); logger.debug('Reading the current configuration from "latest.json"...'); return JSON.parse(fs.readFileSync(packageManifestPath).toString()) || {}; } @@ -40,8 +40,8 @@ export function updateManifestSymlinks( versionFilePath: string, previousVersion: string ): void { - const manifestString = JSON.stringify(updatedManifest, undefined, 2) + "\n"; - logger.debug("Updated manifest", manifestString); + const manifestString = JSON.stringify(updatedManifest, undefined, 2) + '\n'; + logger.debug('Updated manifest', manifestString); logger.debug(`Writing updated manifest to "${versionFilePath}"...`); fs.writeFileSync(versionFilePath, manifestString); createSymlinks(versionFilePath, version, previousVersion); @@ -51,5 +51,5 @@ export function updateManifestSymlinks( * Returns a GithubRemote object to the sentry release registry. */ export function getRegistryGithubRemote(): GithubRemote { - return new GithubRemote("getsentry", "sentry-release-registry"); + return new GithubRemote('getsentry', 'sentry-release-registry'); } diff --git a/src/utils/sentry.ts b/src/utils/sentry.ts index 3f26c5b7..1c021a36 100644 --- a/src/utils/sentry.ts +++ b/src/utils/sentry.ts @@ -1,35 +1,35 @@ -import { arch, hostname, platform, release, userInfo } from "os"; +import { arch, hostname, platform, release, userInfo } from 'os'; -import * as Sentry from "@sentry/node"; +import * as Sentry from '@sentry/node'; -import { logger } from "../logger"; -import { getPackageVersion } from "./version"; +import { logger } from '../logger'; +import { getPackageVersion } from './version'; /** * Initializes Sentry SDK if CRAFT_SENTRY_SDN is set */ export function initSentrySdk(): void { - const sentryDsn = (process.env.CRAFT_SENTRY_DSN || "").trim(); - if (!sentryDsn.startsWith("http")) { + const sentryDsn = (process.env.CRAFT_SENTRY_DSN || '').trim(); + if (!sentryDsn.startsWith('http')) { logger.debug( - "Not initializing Sentry SDK - no valid DSN found in environment or " + - "config files" + 'Not initializing Sentry SDK - no valid DSN found in environment or ' + + 'config files' ); return; } - logger.debug("Sentry DSN found in the environment, initializing the SDK"); + logger.debug('Sentry DSN found in the environment, initializing the SDK'); Sentry.init({ dsn: sentryDsn }); Sentry.configureScope((scope) => { - scope.setTag("os-username", userInfo().username); - scope.setTag("os-hostname", hostname()); - scope.setTag("os-platform", platform()); - scope.setTag("os-arch", arch()); - scope.setTag("os-release", release()); + scope.setTag('os-username', userInfo().username); + scope.setTag('os-hostname', hostname()); + scope.setTag('os-platform', platform()); + scope.setTag('os-arch', arch()); + scope.setTag('os-release', release()); - scope.setExtra("argv", process.argv); - scope.setExtra("craft-version", getPackageVersion()); - scope.setExtra("working-directory", process.cwd()); + scope.setExtra('argv', process.argv); + scope.setExtra('craft-version', getPackageVersion()); + scope.setExtra('working-directory', process.cwd()); }); } diff --git a/src/utils/strings.ts b/src/utils/strings.ts index 79863cd4..2eadeef7 100644 --- a/src/utils/strings.ts +++ b/src/utils/strings.ts @@ -1,5 +1,5 @@ -import * as mustache from "mustache"; -import * as util from "util"; +import * as mustache from 'mustache'; +import * as util from 'util'; /** * Sanitizes object attributes @@ -12,7 +12,7 @@ import * as util from "util"; * @returns Normalized object */ export function sanitizeObject(obj: Record): any { - if (typeof obj !== "object" || obj === null) { + if (typeof obj !== 'object' || obj === null) { throw new Error(`Cannot normalize value: ${obj}`); } @@ -23,17 +23,17 @@ export function sanitizeObject(obj: Record): any { let newValue; // Allowed value types - if (["boolean", "string", "number", "undefined"].indexOf(valueType) > -1) { + if (['boolean', 'string', 'number', 'undefined'].indexOf(valueType) > -1) { newValue = value; } else if (value === null) { newValue = undefined; - } else if (valueType === "object") { + } else if (valueType === 'object') { newValue = sanitizeObject(value); } else { continue; } result[key] = newValue; - const normalizedKey = key.replace(/\./g, "__"); + const normalizedKey = key.replace(/\./g, '__'); if (key !== normalizedKey) { result[normalizedKey] = newValue; } @@ -84,7 +84,7 @@ export function formatSize(size: number): string { // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export function formatJson(obj: any): string { const result = JSON.stringify(obj, null, 4); - if (obj instanceof Error && result === "{}") { + if (obj instanceof Error && result === '{}') { // Error that doesn't implement toJSON() return util.format(obj); } else { diff --git a/src/utils/symlink.ts b/src/utils/symlink.ts index 299ce5bd..feae5e08 100644 --- a/src/utils/symlink.ts +++ b/src/utils/symlink.ts @@ -1,9 +1,9 @@ -import * as fs from "fs"; -import * as path from "path"; +import * as fs from 'fs'; +import * as path from 'path'; -import { logger } from "../logger"; -import { ConfigurationError } from "./errors"; -import { parseVersion, versionGreaterOrEqualThan } from "./version"; +import { logger } from '../logger'; +import { ConfigurationError } from './errors'; +import { parseVersion, versionGreaterOrEqualThan } from './version'; /** * Creates a symlink, overwriting the existing one @@ -54,7 +54,7 @@ export function createSymlinks( logger.debug( `Changing symlink for "latest.json" from version "${oldVersion}" to "${newVersion}"` ); - forceSymlink(baseVersionName, path.join(packageDir, "latest.json")); + forceSymlink(baseVersionName, path.join(packageDir, 'latest.json')); } // link major diff --git a/src/utils/system.ts b/src/utils/system.ts index 15b3a4b5..51a6a0ea 100644 --- a/src/utils/system.ts +++ b/src/utils/system.ts @@ -1,28 +1,28 @@ -import { spawn, SpawnOptions } from "child_process"; -import { createHash, Hash } from "crypto"; -import * as fs from "fs"; -import * as path from "path"; -import split from "split"; -import { Readable } from "stream"; -import tar from "tar"; -import unzipper from "unzipper"; +import { spawn, SpawnOptions } from 'child_process'; +import { createHash, Hash } from 'crypto'; +import * as fs from 'fs'; +import * as path from 'path'; +import split from 'split'; +import { Readable } from 'stream'; +import tar from 'tar'; +import unzipper from 'unzipper'; -import { logger } from "../logger"; +import { logger } from '../logger'; -import { reportError } from "./errors"; -import { downloadSources } from "./githubApi"; -import { isDryRun } from "./helpers"; +import { reportError } from './errors'; +import { downloadSources } from './githubApi'; +import { isDryRun } from './helpers'; /** * Types of supported hashing algorithms */ export enum HashAlgorithm { /** SHA256 */ - SHA256 = "sha256", + SHA256 = 'sha256', /** SHA384 */ - SHA384 = "sha384", + SHA384 = 'sha384', /** SHA512 */ - SHA512 = "sha512", + SHA512 = 'sha512', } /** @@ -30,9 +30,9 @@ export enum HashAlgorithm { */ export enum HashOutputFormat { /** Hex digest, consists of [0-9a-f] characters */ - Hex = "hex", + Hex = 'hex', /** The digest is encoded as base64 string. Used e.g. for Subresource Integrity (SRI) */ - Base64 = "base64", + Base64 = 'base64', } /** @@ -87,14 +87,14 @@ export function replaceEnvVariable( arg: string, env: Record ): string { - if (!env || !arg || arg[0] !== "$") { + if (!env || !arg || arg[0] !== '$') { return arg; } const argLen = arg.length; - if (arg[1] === "{" && arg[argLen - 1] === "}") { + if (arg[1] === '{' && arg[argLen - 1] === '}') { const envVarKey = arg.slice(2, argLen - 1); - return env[envVarKey] || ""; + return env[envVarKey] || ''; } else { return arg; } @@ -132,17 +132,17 @@ export async function spawnProcess( options: SpawnOptions = {}, spawnProcessOptions: SpawnProcessOptions = {} ): Promise { - const argsString = args.map((arg) => `"${arg}"`).join(" "); + const argsString = args.map((arg) => `"${arg}"`).join(' '); if (isDryRun() && !spawnProcessOptions.enableInDryRunMode) { - logger.info("[dry-run] Not spawning process:", `${command} ${argsString}`); + logger.info('[dry-run] Not spawning process:', `${command} ${argsString}`); return undefined; } return new Promise((resolve, reject) => { const stdoutChunks: Buffer[] = []; - let stdout = ""; - let stderr = ""; + let stdout = ''; + let stderr = ''; let child; // NOTE: On Linux, stdout and stderr might flush immediately after the @@ -154,7 +154,7 @@ export async function spawnProcess( reject(processError(e.code, command, args, options, stdout, stderr)); try { - logger.debug("Spawning process:", `${command} ${argsString}`); + logger.debug('Spawning process:', `${command} ${argsString}`); // Do a shell-like replacement of arguments that look like environment variables const processedArgs = args.map((arg) => @@ -162,18 +162,18 @@ export async function spawnProcess( ); // Allow child to accept input - options.stdio = ["inherit", "pipe", "pipe"]; + options.stdio = ['inherit', 'pipe', 'pipe']; child = spawn(command, processedArgs, options); if (!child.stdout || !child.stderr) { - throw new Error("Invalid standard output or error for child process"); + throw new Error('Invalid standard output or error for child process'); } - child.on("exit", (code) => (code === 0 ? succeed() : fail({ code }))); - child.on("error", fail); + child.on('exit', (code) => (code === 0 ? succeed() : fail({ code }))); + child.on('error', fail); - child.stdout.on("data", (chunk: Buffer) => stdoutChunks.push(chunk)); + child.stdout.on('data', (chunk: Buffer) => stdoutChunks.push(chunk)); - child.stdout.pipe(split()).on("data", (data: any) => { + child.stdout.pipe(split()).on('data', (data: any) => { const output = `${command}: ${data}`; if (spawnProcessOptions.showStdout) { logger.info(output); @@ -182,7 +182,7 @@ export async function spawnProcess( } stdout += `${output}\n`; }); - child.stderr.pipe(split()).on("data", (data: any) => { + child.stderr.pipe(split()).on('data', (data: any) => { const output = `${command}: ${data}`; logger.debug(output); stderr += `${output}\n`; @@ -216,9 +216,9 @@ export async function calculateChecksum( const hash = createHash(algorithm); return new Promise((resolve, reject) => { - stream.on("data", (data) => hash.update(data, "utf8")); - stream.on("end", () => resolve(formatDigest(hash, format))); - stream.on("error", reject); + stream.on('data', (data) => hash.update(data, 'utf8')); + stream.on('end', () => resolve(formatDigest(hash, format))); + stream.on('error', reject); }); } @@ -232,10 +232,10 @@ export async function calculateChecksum( function formatDigest(hash: Hash, format: HashOutputFormat): string { switch (format) { case HashOutputFormat.Base64: { - return hash.digest("base64"); + return hash.digest('base64'); } case HashOutputFormat.Hex: { - return hash.digest("hex"); + return hash.digest('hex'); } default: { throw new Error(`Invalid hash format: ${format}`); @@ -258,10 +258,10 @@ export async function sleepAsync(ms: number): Promise { * @param fileName Base name of the given file */ function getPotentialPaths(fileName: string): string[] { - const envPath = process.env.PATH || ""; - const envExt = process.env.PATHEXT || ""; + const envPath = process.env.PATH || ''; + const envExt = process.env.PATHEXT || ''; return envPath - .replace(/"/g, "") + .replace(/"/g, '') .split(path.delimiter) .map((chunk) => envExt @@ -297,7 +297,7 @@ function isExecutable(filePath: string): boolean { */ export function hasExecutable(name: string): boolean { // Relative/absolute path - if (name.indexOf("/") > -1) { + if (name.indexOf('/') > -1) { return isExecutable(name); } const found = getPotentialPaths(name).find(isExecutable) || []; @@ -335,8 +335,8 @@ export async function extractSourcesFromTarStream( try { stream .pipe(tar.extract({ strip: 1, cwd: dir })) - .on("error", reject) - .on("finish", () => { + .on('error', reject) + .on('finish', () => { setTimeout(resolve, 100); }); } catch (e) { @@ -361,8 +361,8 @@ export async function extractZipArchive( try { fs.createReadStream(filePath) .pipe(unzipper.Extract({ strip: 1, path: dir })) - .on("error", reject) - .on("finish", () => { + .on('error', reject) + .on('finish', () => { setTimeout(resolve, 100); }); } catch (e) { @@ -402,15 +402,15 @@ export async function downloadAndExtract( * @param maxTimeDiff Maximum time interval in milliseconds between the signals */ export function catchKeyboardInterrupt(maxTimeDiff = 1000): void { - if (process.env.CRAFT_CATCH_KEYBOARD_INTERRUPT !== "1") { + if (process.env.CRAFT_CATCH_KEYBOARD_INTERRUPT !== '1') { logger.debug( - "Catching Ctrl-C is disabled by default. See https://github.com/getsentry/craft/issues/21" + 'Catching Ctrl-C is disabled by default. See https://github.com/getsentry/craft/issues/21' ); return; } if (!process.stdin.isTTY || !process.stdout.isTTY) { - logger.debug("stdin or stdout is not a TTY, not catching SIGINTs"); + logger.debug('stdin or stdout is not a TTY, not catching SIGINTs'); return; } @@ -419,20 +419,20 @@ export function catchKeyboardInterrupt(maxTimeDiff = 1000): void { // the external "yarn" process is killed, and no longer attached to stdout, // while the craft process receives only one SIGINT. // Hence, we're trying to detect if we run the script via yarn/npm. - if ((process.env.npm_package_scripts_cli || "").indexOf("node") > -1) { - logger.debug("NPM/Yarn script environment detected, not catching SIGINTs"); + if ((process.env.npm_package_scripts_cli || '').indexOf('node') > -1) { + logger.debug('NPM/Yarn script environment detected, not catching SIGINTs'); return; } - logger.debug("Setting custom SIGINT handler"); + logger.debug('Setting custom SIGINT handler'); let lastSignalTime = 0; - process.on("SIGINT", () => { + process.on('SIGINT', () => { const now = Date.now(); if (lastSignalTime && now - lastSignalTime <= maxTimeDiff) { - logger.warn("Got ^C, exiting."); + logger.warn('Got ^C, exiting.'); process.exit(1); } else { - logger.warn("Press ^C again (quickly!) to exit."); + logger.warn('Press ^C again (quickly!) to exit.'); lastSignalTime = now; } }); diff --git a/src/utils/version.ts b/src/utils/version.ts index d164469c..9b4e32b9 100644 --- a/src/utils/version.ts +++ b/src/utils/version.ts @@ -1,4 +1,4 @@ -import { getGitTagPrefix } from "../config"; +import { getGitTagPrefix } from '../config'; /** * Regular expression for matching semver versions @@ -23,7 +23,7 @@ const semverRegex = () => export function getVersion(text: string): string | null { const matches = semverRegex().exec(text); const version = matches && matches[0]; - return version && version[0].toLowerCase() === "v" + return version && version[0].toLowerCase() === 'v' ? version.substr(1) : version; } @@ -137,10 +137,10 @@ export function versionToTag(version: string, tagPrefix?: string): string { * Reads "package.json" from project root and returns its contents */ export function getPackage(): any { - const pkg = require("../../package.json") || {}; + const pkg = require('../../package.json') || {}; // Sanity check if (Object.keys(pkg).length === 0) { - throw new Error("Invalid package.json: the file is empty!"); + throw new Error('Invalid package.json: the file is empty!'); } return pkg; } From 08c52cec33e93e41fa448a5acd08dc1f1ee656f5 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 3 May 2021 13:38:06 +0300 Subject: [PATCH 10/14] avoid arrow function parens --- .prettierrc | 1 - .prettierrc.yml | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 .prettierrc create mode 100644 .prettierrc.yml diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 63778788..00000000 --- a/.prettierrc +++ /dev/null @@ -1 +0,0 @@ -{ "singleQuote": true } diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 00000000..44645dcb --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1,2 @@ +singleQuote: true +arrowParens: avoid From dd21dc88595ebf06526cc41cbd4bbab31bc5973a Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 3 May 2021 14:02:11 +0300 Subject: [PATCH 11/14] fix readme indentation --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dcf57a13..15099974 100644 --- a/README.md +++ b/README.md @@ -958,8 +958,8 @@ Here is how you can integrate your GitHub project with `craft`: 3. Add `.craft.yml` configuration file to your project -- List there all the targets you want to publish to -- Configure additional options (changelog management policy, tag prefix, etc.) + - List there all the targets you want to publish to + - Configure additional options (changelog management policy, tag prefix, etc.) 4. Add a [pre-release script](#pre-release-version-bumping-script-conventions) to your project. 5. Get various [configuration tokens](#global-configuration) From 3a24f6d73acfb11a639ce405bb8fd8ff50a0c28c Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 3 May 2021 15:14:06 +0300 Subject: [PATCH 12/14] latent lint fixes --- src/artifact_providers/zeus.ts | 2 +- src/stores/zeus.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/artifact_providers/zeus.ts b/src/artifact_providers/zeus.ts index ac5eb34d..e85395a9 100644 --- a/src/artifact_providers/zeus.ts +++ b/src/artifact_providers/zeus.ts @@ -172,6 +172,6 @@ export class ZeusArtifactProvider extends BaseArtifactProvider { return dict; }, {} as { [key: string]: ZeusArtifact }) - ).map((zeusArtifact) => this.convertToRemoteArtifact(zeusArtifact));; + ).map(zeusArtifact => this.convertToRemoteArtifact(zeusArtifact)); } } diff --git a/src/stores/zeus.ts b/src/stores/zeus.ts index 673cc29e..41f369de 100644 --- a/src/stores/zeus.ts +++ b/src/stores/zeus.ts @@ -117,7 +117,7 @@ export class ZeusStore { */ public async downloadArtifacts(artifacts: Artifact[]): Promise { return Promise.all( - artifacts.map(async (artifact) => this.downloadArtifact(artifact)) + artifacts.map(async artifact => this.downloadArtifact(artifact)) ); } @@ -176,13 +176,13 @@ export class ZeusStore { } const { includeNames, excludeNames } = filterOptions; if (includeNames) { - filteredArtifacts = filteredArtifacts.filter((artifact) => + filteredArtifacts = filteredArtifacts.filter(artifact => includeNames.test(artifact.name) ); } if (excludeNames) { filteredArtifacts = filteredArtifacts.filter( - (artifact) => !excludeNames.test(artifact.name) + artifact => !excludeNames.test(artifact.name) ); } return filteredArtifacts; From 40258c256484e7e4b8f2a795b628396ae48e7f52 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 3 May 2021 15:59:05 +0300 Subject: [PATCH 13/14] I surrender --- .github/workflows/lint.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f3208d36..f07d855a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -20,7 +20,7 @@ jobs: if: steps.cache.outputs.cache-hit != 'true' run: yarn install --frozen-lockfile - name: Lint - run: yarn lint + run: yarn lint:fix - name: Save lint fixes run: > git config user.email "bot@sentry.io" && diff --git a/package.json b/package.json index da36794a..ad52bdb4 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "precli": "build", "cli": "node dist/craft", "clean": "rimraf dist coverage", - "lint": "prettier --write .", + "lint:fix": "prettier --write .", "test": "jest", "test:watch": "jest --watch --notify", "compile-config-schema": "node ./scripts/config-json-schema-to-ts.js" From 4304f15499be3cf6d7b57e0866234709fefac36a Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 3 May 2021 16:00:20 +0300 Subject: [PATCH 14/14] it is fix, not lint:fix --- .github/workflows/lint.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f07d855a..c62d8752 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -20,7 +20,7 @@ jobs: if: steps.cache.outputs.cache-hit != 'true' run: yarn install --frozen-lockfile - name: Lint - run: yarn lint:fix + run: yarn fix - name: Save lint fixes run: > git config user.email "bot@sentry.io" && diff --git a/package.json b/package.json index ad52bdb4..eea8ae56 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "precli": "build", "cli": "node dist/craft", "clean": "rimraf dist coverage", - "lint:fix": "prettier --write .", + "fix": "prettier --write .", "test": "jest", "test:watch": "jest --watch --notify", "compile-config-schema": "node ./scripts/config-json-schema-to-ts.js"