diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml new file mode 100644 index 0000000..1b133d6 --- /dev/null +++ b/.github/workflows/pr.yaml @@ -0,0 +1,17 @@ +name: Pull Request +on: pull_request + +jobs: + tests: + runs-on: ubuntu-latest + name: Run Tests + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Bazel + uses: bazelbuild/setup-bazelisk@v2 + + - name: Run Tests + run: | + bazel run //tests:test_image diff --git a/README.md b/README.md index 7bdb58c..9dcd002 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ dependent PRs; no more waiting for your backend changes to test before landing y ### How it Works -After creating a MergeGraph [app.trunk.io](app.trunk.io), simply comment `/trunk merge` on your PRs -to submit it to the graph. Once the graph has passed the prerequisites to be admitted into the graph -(impacted targets have been uploaded, Github deems the PR mergeable), the Trunk Service will +After creating a MergeGraph at [app.trunk.io](app.trunk.io), simply comment `/trunk merge` on your +PRs to submit it to the graph. Once the graph has passed the prerequisites to be admitted into the +graph (impacted targets have been uploaded, Github deems the PR mergeable), the Trunk Service will en-graph the PR, constructing a test branch between the PR and all of its ancestors. On successful completion of tests, Trunk merges the PR, keeping your main branch green 😎. @@ -41,6 +41,10 @@ jobs: +### Tests + +`bazel run //tests:test_image` + ### What is an Impacted Target? An impacted target is a unit that is affected by a particular PR. For example, a change at diff --git a/action.yaml b/action.yaml index 4aea2ec..03eb18c 100644 --- a/action.yaml +++ b/action.yaml @@ -35,7 +35,7 @@ runs: - name: Prerequisites id: prerequisites - run: ${GITHUB_ACTION_PATH}/prerequisites.sh + run: ${GITHUB_ACTION_PATH}/src/scripts/prerequisites.sh shell: bash env: TARGET_BRANCH: ${{ inputs.target-branch }} @@ -43,7 +43,7 @@ runs: - name: Compute Impacted Targets id: compute-impacted-targets - run: ${GITHUB_ACTION_PATH}/compute_impacted_targets.sh + run: ${GITHUB_ACTION_PATH}/src/scripts/compute_impacted_targets.sh shell: bash env: MERGE_INSTANCE_BRANCH: ${{ steps.prerequisites.outputs.merge_instance_branch }} @@ -51,7 +51,7 @@ runs: VERBOSE: ${{ inputs.verbose }} - name: Upload Impacted Targets - run: ${GITHUB_ACTION_PATH}/upload_impacted_targets.sh + run: ${GITHUB_ACTION_PATH}/src/scripts/upload_impacted_targets.sh shell: bash env: ACTOR: ${{ github.actor }} diff --git a/package.json b/package.json index 16eca0b..9fdf04f 100644 --- a/package.json +++ b/package.json @@ -12,12 +12,20 @@ }, "dependencies": { "@types/node": "20.4.2", - "typescript": "5.1.6" + "typescript": "5.1.6", + "zod": "3.21.4" }, "devDependencies": { "@types/chai": "4.3.5", + "@types/chai-as-promised": "7.1.5", + "@types/express": "4.17.17", + "@types/lodash": "4.14.195", "@types/mocha": "10.0.1", "chai": "4.3.7", + "chai-as-promised": "7.1.1", + "express": "4.18.2", + "http-status-codes": "2.2.0", + "lodash": "4.17.21", "mocha": "10.2.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 788e51c..9b868e4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,34 +11,141 @@ dependencies: typescript: specifier: 5.1.6 version: 5.1.6 + zod: + specifier: 3.21.4 + version: 3.21.4 devDependencies: '@types/chai': specifier: 4.3.5 version: 4.3.5 + '@types/chai-as-promised': + specifier: 7.1.5 + version: 7.1.5 + '@types/express': + specifier: 4.17.17 + version: 4.17.17 + '@types/lodash': + specifier: 4.14.195 + version: 4.14.195 '@types/mocha': specifier: 10.0.1 version: 10.0.1 chai: specifier: 4.3.7 version: 4.3.7 + chai-as-promised: + specifier: 7.1.1 + version: 7.1.1(chai@4.3.7) + express: + specifier: 4.18.2 + version: 4.18.2 + http-status-codes: + specifier: 2.2.0 + version: 2.2.0 + lodash: + specifier: 4.17.21 + version: 4.17.21 mocha: specifier: 10.2.0 version: 10.2.0 packages: + /@types/body-parser@1.19.2: + resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} + dependencies: + '@types/connect': 3.4.35 + '@types/node': 20.4.2 + dev: true + + /@types/chai-as-promised@7.1.5: + resolution: {integrity: sha512-jStwss93SITGBwt/niYrkf2C+/1KTeZCZl1LaeezTlqppAKeoQC7jxyqYuP72sxBGKCIbw7oHgbYssIRzT5FCQ==} + dependencies: + '@types/chai': 4.3.5 + dev: true + /@types/chai@4.3.5: resolution: {integrity: sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==} dev: true + /@types/connect@3.4.35: + resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} + dependencies: + '@types/node': 20.4.2 + dev: true + + /@types/express-serve-static-core@4.17.35: + resolution: {integrity: sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==} + dependencies: + '@types/node': 20.4.2 + '@types/qs': 6.9.7 + '@types/range-parser': 1.2.4 + '@types/send': 0.17.1 + dev: true + + /@types/express@4.17.17: + resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==} + dependencies: + '@types/body-parser': 1.19.2 + '@types/express-serve-static-core': 4.17.35 + '@types/qs': 6.9.7 + '@types/serve-static': 1.15.2 + dev: true + + /@types/http-errors@2.0.1: + resolution: {integrity: sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==} + dev: true + + /@types/lodash@4.14.195: + resolution: {integrity: sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==} + dev: true + + /@types/mime@1.3.2: + resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==} + dev: true + + /@types/mime@3.0.1: + resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==} + dev: true + /@types/mocha@10.0.1: resolution: {integrity: sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==} dev: true /@types/node@20.4.2: resolution: {integrity: sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==} - dev: false + + /@types/qs@6.9.7: + resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==} + dev: true + + /@types/range-parser@1.2.4: + resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==} + dev: true + + /@types/send@0.17.1: + resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==} + dependencies: + '@types/mime': 1.3.2 + '@types/node': 20.4.2 + dev: true + + /@types/serve-static@1.15.2: + resolution: {integrity: sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==} + dependencies: + '@types/http-errors': 2.0.1 + '@types/mime': 3.0.1 + '@types/node': 20.4.2 + dev: true + + /accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + dev: true /ansi-colors@4.1.1: resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} @@ -69,6 +176,10 @@ packages: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true + /array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + dev: true + /assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} dev: true @@ -82,6 +193,26 @@ packages: engines: {node: '>=8'} dev: true + /body-parser@1.20.1: + resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.1 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: true + /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -106,11 +237,32 @@ packages: resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} dev: true + /bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + dev: true + + /call-bind@1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + dependencies: + function-bind: 1.1.1 + get-intrinsic: 1.2.1 + dev: true + /camelcase@6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} dev: true + /chai-as-promised@7.1.1(chai@4.3.7): + resolution: {integrity: sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==} + peerDependencies: + chai: '>= 2.1.2 < 5' + dependencies: + chai: 4.3.7 + check-error: 1.0.2 + dev: true + /chai@4.3.7: resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==} engines: {node: '>=4'} @@ -174,6 +326,38 @@ packages: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: true + /content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + dev: true + + /cookie-signature@1.0.6: + resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + dev: true + + /cookie@0.5.0: + resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + engines: {node: '>= 0.6'} + dev: true + + /debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.0.0 + dev: true + /debug@4.3.4(supports-color@8.1.1): resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -199,25 +383,92 @@ packages: type-detect: 4.0.8 dev: true + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dev: true + + /destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dev: true + /diff@5.0.0: resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} engines: {node: '>=0.3.1'} dev: true + /ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + dev: true + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true + /encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + dev: true + /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} dev: true + /escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + dev: true + /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} dev: true + /etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + dev: true + + /express@4.18.2: + resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==} + engines: {node: '>= 0.10.0'} + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.1 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.5.0 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.2.0 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.1 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.7 + proxy-addr: 2.0.7 + qs: 6.11.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.18.0 + serve-static: 1.15.0 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + dev: true + /fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} @@ -225,6 +476,21 @@ packages: to-regex-range: 5.0.1 dev: true + /finalhandler@1.2.0: + resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} + engines: {node: '>= 0.8'} + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: true + /find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -238,6 +504,16 @@ packages: hasBin: true dev: true + /forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + dev: true + + /fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + dev: true + /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true @@ -250,6 +526,10 @@ packages: dev: true optional: true + /function-bind@1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + dev: true + /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -259,6 +539,15 @@ packages: resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} dev: true + /get-intrinsic@1.2.1: + resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-proto: 1.0.1 + has-symbols: 1.0.3 + dev: true + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -282,11 +571,50 @@ packages: engines: {node: '>=8'} dev: true + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: true + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: true + + /has@1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + dependencies: + function-bind: 1.1.1 + dev: true + /he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true dev: true + /http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + dev: true + + /http-status-codes@2.2.0: + resolution: {integrity: sha512-feERVo9iWxvnejp3SEfm/+oNG517npqL2/PIA8ORjyOZjGC7TwCRQsZylciLS64i6pJ0wRYz3rkXLRwbtFa8Ng==} + dev: true + + /iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: true + /inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} dependencies: @@ -298,6 +626,11 @@ packages: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} dev: true + /ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + dev: true + /is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -351,6 +684,10 @@ packages: p-locate: 5.0.0 dev: true + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + /log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} @@ -365,6 +702,38 @@ packages: get-func-name: 2.0.0 dev: true + /media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + dev: true + + /merge-descriptors@1.0.1: + resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} + dev: true + + /methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + dev: true + + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: true + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: true + + /mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + dev: true + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -406,6 +775,10 @@ packages: yargs-unparser: 2.0.0 dev: true + /ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + dev: true + /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true @@ -420,11 +793,27 @@ packages: hasBin: true dev: true + /negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + dev: true + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} dev: true + /object-inspect@1.12.3: + resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + dev: true + + /on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + dependencies: + ee-first: 1.1.1 + dev: true + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: @@ -445,6 +834,11 @@ packages: p-limit: 3.1.0 dev: true + /parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + dev: true + /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -455,6 +849,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /path-to-regexp@0.1.7: + resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} + dev: true + /pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} dev: true @@ -464,12 +862,42 @@ packages: engines: {node: '>=8.6'} dev: true + /proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + dev: true + + /qs@6.11.0: + resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + dev: true + /randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: safe-buffer: 5.2.1 dev: true + /range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + dev: true + + /raw-body@2.5.1: + resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==} + engines: {node: '>= 0.8'} + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + dev: true + /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -486,12 +914,66 @@ packages: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} dev: true + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: true + + /send@0.18.0: + resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} + engines: {node: '>= 0.8.0'} + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: true + /serialize-javascript@6.0.0: resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} dependencies: randombytes: 2.1.0 dev: true + /serve-static@1.15.0: + resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} + engines: {node: '>= 0.8.0'} + dependencies: + encodeurl: 1.0.2 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.18.0 + transitivePeerDependencies: + - supports-color + dev: true + + /setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + dev: true + + /side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + object-inspect: 1.12.3 + dev: true + + /statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + dev: true + /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -534,17 +1016,45 @@ packages: is-number: 7.0.0 dev: true + /toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + dev: true + /type-detect@4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} dev: true + /type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + dev: true + /typescript@5.1.6: resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} engines: {node: '>=14.17'} hasBin: true dev: false + /unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + dev: true + + /utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + dev: true + + /vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + dev: true + /workerpool@6.2.1: resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} dev: true @@ -599,3 +1109,7 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} dev: true + + /zod@3.21.4: + resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} + dev: false diff --git a/src/scripts/BUILD b/src/scripts/BUILD new file mode 100644 index 0000000..747321f --- /dev/null +++ b/src/scripts/BUILD @@ -0,0 +1,9 @@ +filegroup( + name = "scripts", + srcs = [ + "compute_impacted_targets.sh", + "prerequisites.sh", + "upload_impacted_targets.sh", + ], + visibility = ["//tests:__subpackages__"], +) diff --git a/compute_impacted_targets.sh b/src/scripts/compute_impacted_targets.sh similarity index 100% rename from compute_impacted_targets.sh rename to src/scripts/compute_impacted_targets.sh diff --git a/prerequisites.sh b/src/scripts/prerequisites.sh similarity index 100% rename from prerequisites.sh rename to src/scripts/prerequisites.sh diff --git a/upload_impacted_targets.sh b/src/scripts/upload_impacted_targets.sh similarity index 100% rename from upload_impacted_targets.sh rename to src/scripts/upload_impacted_targets.sh diff --git a/tests/BUILD b/tests/BUILD new file mode 100644 index 0000000..441d1b1 --- /dev/null +++ b/tests/BUILD @@ -0,0 +1,67 @@ +load("//toolchain/docker:defs.bzl", "trunk_container_image", "trunk_container_run_and_commit", "trunk_nodejs_container_image") +load("//toolchain/node:defs.bzl", "trunk_js_binary", "trunk_ts_lib", "trunk_ts_test") + +package( + default_visibility = ["//visibility:private"], +) + +trunk_container_run_and_commit( + name = "nodejs_image_with_utils", + commands = [ + "apt update && apt install -y " + " ".join([ + "curl", + "jq", + ]) + " && rm -rf /var/lib/apt/lists/*", + ], + image = "@debian11//image", +) + +trunk_ts_lib( + name = "lib", + srcs = ["upload.test.ts"], + deps = [ + "//:node_modules/@types/chai", + "//:node_modules/@types/chai-as-promised", + "//:node_modules/@types/express", + "//:node_modules/@types/lodash", + "//:node_modules/@types/mocha", + "//:node_modules/chai", + "//:node_modules/chai-as-promised", + "//:node_modules/express", + "//:node_modules/http-status-codes", + "//:node_modules/lodash", + "//:node_modules/mocha", + "//:node_modules/zod", + ], +) + +trunk_js_binary( + name = "bin", + data = [":lib"], + entry_point = "upload.test.js", +) + +trunk_ts_test( + name = "test", + srcs = ["upload.test.ts"], + data = [":bin"], +) + +# Dockerize the Test +trunk_nodejs_container_image( + name = "nodejs_test", + testonly = True, + args = ["src/**/upload.test.ts"], + base = ":nodejs_image_with_utils", + binary = ":test", +) + +trunk_container_image( + name = "test_image", + testonly = True, + base = ":nodejs_test", + cmd = ["__main__/tests/upload.test.js"], + entrypoint = "bash /app/{}/test".format(package_name()).split(" "), + files = ["//src/scripts"], + workdir = "/app/{}/test.runfiles".format(package_name()), +) diff --git a/tests/upload.test.ts b/tests/upload.test.ts new file mode 100644 index 0000000..5679624 --- /dev/null +++ b/tests/upload.test.ts @@ -0,0 +1,170 @@ +/** Test the compute_impacted_targets actions. */ +import chai from "chai"; +import chaiAsPromised from "chai-as-promised"; +import express from "express"; +import { StatusCodes } from "http-status-codes"; +import * as _ from "lodash"; +import { strict as assert } from "node:assert"; +import exec from "node:child_process"; +import fs from "node:fs"; +import http from "node:http"; +import util from "node:util"; +import { z } from "zod"; + +chai.use(chaiAsPromised); +const { expect } = chai; + +const PORT = 4567; + +const fetchUrl = (path: string) => `http://localhost:${PORT}${path}`; +const UPLOAD_IMPACTED_TARGETS_SCRIPT = "/upload_impacted_targets.sh"; +const ENV_VARIABLES: Record = { + API_TOKEN: "test-api-token", + REPOSITORY: "test-repo-owner/test-repo-name", + TARGET_BRANCH: "test-target-branch", + PR_NUMBER: "123", + PR_SHA: "test-pr-sha", + IMPACTED_TARGETS_FILE: "/test-impacted-targets-file", + API_URL: fetchUrl("/testUploadImpactedTargets"), +}; + +const SCHEMA = z.object({ + repo: z.object({ + host: z.string(), + owner: z.string(), + name: z.string(), + }), + pr: z.object({ + number: z.string(), + sha: z.string(), + }), + targetBranch: z.string(), + impactedTargets: z.array(z.string()), +}); + +const exportEnv = (env: Record) => + Object.entries(env) + .map(([key, value]) => `${key}=${value}`) + .join(" "); + +describe("ComputeImpactedTargetsAction", function () { + let server: http.Server; + // x-api-token, body + let uploadedImpactedTargetsPayload = [null, null]; + + // Start an HTTP Server with a single endpoint. + before(function () { + const app = express(); + + app.use(express.json({ limit: "10mb" })); + + app.post("/testUploadImpactedTargets", (req, res) => { + const actualApiToken = req.headers["x-api-token"]; + uploadedImpactedTargetsPayload = [actualApiToken, req.body]; + + res.sendStatus( + actualApiToken === ENV_VARIABLES.API_TOKEN ? StatusCodes.OK : StatusCodes.UNAUTHORIZED, + ); + }); + + server = app.listen(PORT, () => console.debug("Server listening on %d", PORT)); + }); + + beforeEach(function () { + uploadedImpactedTargetsPayload = [null, null]; + }); + + after(function () { + server.close(); + }); + + context("UploadImpactedTargets", function () { + const expectImpactedTargetsUpload = (impactedTargets: string[]): void => { + const { API_TOKEN, REPOSITORY, TARGET_BRANCH, PR_NUMBER, PR_SHA } = ENV_VARIABLES; + const [actualToken, actualBody] = uploadedImpactedTargetsPayload; + expect(actualToken).to.equal(API_TOKEN); + expect(SCHEMA.parse(actualBody)).to.deep.equal({ + repo: { + host: "github.com", + owner: REPOSITORY.split("/")[0], + name: REPOSITORY.split("/")[1], + }, + pr: { + number: PR_NUMBER, + sha: PR_SHA, + }, + targetBranch: TARGET_BRANCH, + impactedTargets, + }); + }; + + const runUploadTargets = async ( + impactedTargets: string[], + env: Record = ENV_VARIABLES, + shouldPass = true, + ) => { + // The bazel / glob / ... scripts are responsible for populating these files. + // Verify that the upload works as intended. + fs.writeFileSync(env.IMPACTED_TARGETS_FILE, impactedTargets.join("\n")); + + const runScript = util.promisify(exec.exec)( + `${exportEnv(env)} ${UPLOAD_IMPACTED_TARGETS_SCRIPT}`, + ); + + if (shouldPass) { + await expect(runScript).to.eventually.be.fulfilled; + } else { + await expect(runScript).to.eventually.be.rejected; + } + }; + + afterEach(function () { + fs.rmSync(ENV_VARIABLES.IMPACTED_TARGETS_FILE, { force: true }); + }); + + it("rejects if missing required input", function () { + expect(() => exec.execFileSync(UPLOAD_IMPACTED_TARGETS_SCRIPT)).to.throw; + }); + + it("hits the endpoint", async function () { + const impactedTargets = ["target-1", "target-2", "target-3"]; + await runUploadTargets(impactedTargets); + expectImpactedTargetsUpload(impactedTargets); + }); + + it("supports empty targets", async function () { + const impactedTargets: string[] = []; + await runUploadTargets(impactedTargets); + expectImpactedTargetsUpload(impactedTargets); + }); + + it("supports 1K targets", async function () { + const impactedTargets = [...new Array(1_000)].map((_, i) => `target-${i}`); + await runUploadTargets(impactedTargets); + expectImpactedTargetsUpload(impactedTargets); + }); + + it("supports 100K targets", async function () { + const impactedTargets = [...new Array(1_000)].map((_, i) => `target-${i}`); + await runUploadTargets(impactedTargets); + expectImpactedTargetsUpload(impactedTargets); + }); + + context("on error", function () { + context("authn error", function () { + const ENV_MALFORMED_API_TOKEN: Record = { + ...ENV_VARIABLES, + API_TOKEN: " ", + }; + + it("on missing API token", async function () { + await runUploadTargets([], _.omit(ENV_VARIABLES, "API_TOKEN"), false); + }); + + it("on 401 error", async function () { + await runUploadTargets([], ENV_MALFORMED_API_TOKEN, false); + }); + }); + }); + }); +}); diff --git a/toolchain/docker/defs.bzl b/toolchain/docker/defs.bzl index 2ae14e5..2c9f852 100644 --- a/toolchain/docker/defs.bzl +++ b/toolchain/docker/defs.bzl @@ -1,9 +1,18 @@ load("@aspect_rules_js//js:defs.bzl", "js_image_layer") load("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_layer") +load("@io_bazel_rules_docker//docker/util:run.bzl", "container_run_and_commit") def trunk_container_image(name, tags = [], legacy_run_behavior = False, **kwargs): container_image(name = name, tags = tags, legacy_run_behavior = legacy_run_behavior, **kwargs) +def trunk_container_run_and_commit(name, tags = [], visibility = ["//visibility:public"], **kwargs): + container_run_and_commit( + name = name, + tags = tags, + visibility = visibility, + **kwargs + ) + def trunk_nodejs_container_image(name, binary, tags = [], layers = [], base = "@debian11//image", visibility = ["//visibility:public"], testonly = False, **kwargs): layers_name = name + "_layers" js_image_layer(