diff --git a/.github/workflows/_mirror-distribution.yml b/.github/workflows/_mirror-distribution.yml index 63402d56..b2fbf52b 100644 --- a/.github/workflows/_mirror-distribution.yml +++ b/.github/workflows/_mirror-distribution.yml @@ -25,13 +25,13 @@ jobs: versions: ${{ steps.get-unmirrored-versions.outputs.versions }} steps: - name: Checkout Repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Update Rust toolchain run: rustup update - name: Rust Cache - uses: Swatinem/rust-cache@v2.6.2 + uses: Swatinem/rust-cache@v2.7.0 - name: Get unmirrored versions id: get-unmirrored-versions @@ -51,7 +51,7 @@ jobs: include: ${{ fromJson(inputs.distribution == 'node' && '[{"platform":"linux-x64"}]' || '[]') }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Download and verify distribution run: | diff --git a/.github/workflows/_update-inventory.yml b/.github/workflows/_update-inventory.yml index c5d6d4ce..4fb98a62 100644 --- a/.github/workflows/_update-inventory.yml +++ b/.github/workflows/_update-inventory.yml @@ -34,7 +34,7 @@ jobs: private_key: ${{ secrets.LINGUIST_GH_PRIVATE_KEY }} - name: Checkout Repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: token: ${{ steps.generate-token.outputs.app_token }} @@ -42,7 +42,7 @@ jobs: run: rustup update - name: Rust cache - uses: Swatinem/rust-cache@v2.6.2 + uses: Swatinem/rust-cache@v2.7.0 - name: Set Diff Message id: set-diff-msg diff --git a/.github/workflows/check_changelog.yml b/.github/workflows/check_changelog.yml index 31ca446a..e1e09400 100644 --- a/.github/workflows/check_changelog.yml +++ b/.github/workflows/check_changelog.yml @@ -18,7 +18,7 @@ jobs: !contains(github.event.pull_request.labels.*.name, 'dependencies') steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check that CHANGELOG is touched run: | git fetch origin ${{ github.base_ref }} --depth 1 && \ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8f74d14..3dc69917 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: steps: - run: apk add git - run: apk add shfmt --repository=http://dl-3.alpinelinux.org/alpine/edge/community - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: shellcheck run: shfmt -f . | grep -v ^test/ | xargs shellcheck - name: shfmt @@ -27,11 +27,11 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Update Rust toolchain run: rustup update - name: Rust Cache - uses: Swatinem/rust-cache@v2.6.2 + uses: Swatinem/rust-cache@v2.7.0 - name: Clippy run: cargo clippy --all-targets --locked -- --deny warnings - name: rustfmt @@ -41,11 +41,11 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Update Rust toolchain run: rustup update - name: Rust Cache - uses: Swatinem/rust-cache@v2.6.2 + uses: Swatinem/rust-cache@v2.7.0 - name: Run unit tests run: cargo test --locked @@ -53,27 +53,33 @@ jobs: name: Find libcnb buildpacks runs-on: ubuntu-22.04 outputs: - buildpack_dirs: ${{ steps.find-buildpack-dirs.outputs.buildpack_dirs }} + libcnb-buildpacks: ${{ steps.find-buildpack-dirs.outputs.buildpacks }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: true - id: find-buildpack-dirs name: Find libcnb buildpack directories - run: echo "buildpack_dirs=$(find . -type d -execdir test -e "{}/buildpack.toml" -a -e "{}/Cargo.toml" \; -print | sort | uniq | jq -nRc '[inputs]')" >> $GITHUB_OUTPUT + run: | + echo "buildpacks=$( \ + find . -type d -execdir test -e "{}/buildpack.toml" -a -e "{}/Cargo.toml" \; -print \ + | sort \ + | uniq \ + | jq -nRc '[inputs] | map({ dir: ., name: split("/") | last } | [. + { builder_tag: 20 }, . + { builder_tag: 22 }]) | flatten' \ + )" >> $GITHUB_OUTPUT rust-integration-test: - name: libcnb.rs integration tests (${{ matrix.buildpack-directory }}) + name: Test (${{ matrix.builder_tag }}, ${{ matrix.name }}) runs-on: pub-hk-ubuntu-22.04-large needs: find-libcnb-buildpacks strategy: fail-fast: false matrix: - buildpack-directory: ${{ fromJson(needs.find-libcnb-buildpacks.outputs.buildpack_dirs) }} + include: ${{ fromJson(needs.find-libcnb-buildpacks.outputs.libcnb-buildpacks) }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install musl-tools run: sudo apt-get install musl-tools --no-install-recommends - name: Update Rust toolchain @@ -81,11 +87,13 @@ jobs: - name: Install Rust linux-musl target run: rustup target add x86_64-unknown-linux-musl - name: Rust Cache - uses: Swatinem/rust-cache@v2.6.2 + uses: Swatinem/rust-cache@v2.7.0 - name: Install Pack CLI uses: buildpacks/github-actions/setup-pack@v5.4.0 - name: Run integration tests - working-directory: ${{ matrix.buildpack-directory }} + working-directory: ${{ matrix.dir }} + env: + INTEGRATION_TEST_CNB_BUILDER: heroku/builder:${{ matrix.builder_tag }} run: cargo test --locked -- --ignored --test-threads 16 shpec: @@ -95,49 +103,17 @@ jobs: strategy: matrix: stack-version: - - '20' - - '22' + - '20' + - '22' buildpack-dir: - - buildpacks/npm + - buildpacks/npm defaults: run: shell: bash steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install shpec run: sh -c "`curl -L https://raw.githubusercontent.com/rylnd/shpec/master/install.sh`" - name: Shpec unit tests on heroku-${{ matrix.stack-version }} run: shpec ${{ matrix.buildpack-dir }}/shpec/*_shpec.sh - - cutlass-integration-test: - runs-on: ubuntu-22.04 - strategy: - matrix: - test-dir: - - test/specs/node-function - - test/specs/node - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Set up Ruby, bundler, and cache - uses: ruby/setup-ruby@v1 - with: - ruby-version: 3.0.2 - bundler-cache: true - - name: Install musl-tools - run: sudo apt-get install musl-tools --no-install-recommends - - name: Update Rust toolchain - run: rustup update - - name: Install Rust linux-musl target - run: rustup target add x86_64-unknown-linux-musl - - name: Rust Cache - uses: Swatinem/rust-cache@v2.6.2 - - name: Install libcnb - run: cargo install libcnb-cargo - - name: Install Pack CLI - uses: buildpacks/github-actions/setup-pack@v5.4.0 - - name: Install yj - uses: buildpacks/github-actions/setup-tools@v5.4.0 - - name: Run rspec tests against a given directory - run: bundle exec rspec ${{ matrix.test-dir }} diff --git a/.rspec b/.rspec deleted file mode 100644 index 7aac1efb..00000000 --- a/.rspec +++ /dev/null @@ -1 +0,0 @@ ---require dead_end diff --git a/Cargo.lock b/Cargo.lock index 8eb19487..07e3ae40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,6 +48,17 @@ dependencies = [ "regex", ] +[[package]] +name = "async-trait" +version = "0.1.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -96,6 +107,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bstr" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "bumpalo" version = "3.13.0" @@ -150,6 +171,20 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cargo_metadata" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb9ac64500cc83ce4b9f8dafa78186aa008c8dea77a09b94cd307fd0cd5022a8" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cc" version = "1.0.82" @@ -167,16 +202,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.28" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", - "time", "wasm-bindgen", "windows-targets", ] @@ -184,18 +218,19 @@ dependencies = [ [[package]] name = "commons" version = "0.1.0" -source = "git+https://github.com/heroku/buildpacks-ruby?branch=schneems/logging-state-machine-continued#2b561820544cc70b74ca257be07f054be925fd1d" +source = "git+https://github.com/heroku/buildpacks-ruby?branch=schneems/logging-state-machine-continued#64c7e62c13ba9c80e928783256c6c7b3c736fd2b" dependencies = [ "ascii_table", "byte-unit", + "const_format", "fancy-regex", "fs-err", "fs_extra", "glob", "indoc", "lazy_static", - "libcnb", - "libherokubuildpack", + "libcnb 0.14.0", + "libherokubuildpack 0.14.0", "regex", "serde", "sha2", @@ -205,6 +240,26 @@ dependencies = [ "which_problem", ] +[[package]] +name = "const_format" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c990efc7a285731f9a4378d81aff2f0e85a2c8781a05ef0f8baa8dac54d0ff48" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e026b6ce194a874cb9cf32cd5772d1ef9767cc8fcb5765948d74f37a9d8b2bf6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -397,6 +452,70 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-core", + "futures-macro", + "futures-sink", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -407,12 +526,36 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "globset" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -425,21 +568,16 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" -[[package]] -name = "hermit-abi" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" - [[package]] name = "heroku-nodejs-corepack-buildpack" version = "0.0.0" dependencies = [ "heroku-nodejs-utils", "indoc", - "libcnb", + "libcnb 0.15.0", "libcnb-test", - "libherokubuildpack", + "libherokubuildpack 0.15.0", + "opentelemetry", "serde", "test_support", "thiserror", @@ -451,13 +589,15 @@ name = "heroku-nodejs-engine-buildpack" version = "0.0.0" dependencies = [ "heroku-nodejs-utils", - "libcnb", + "libcnb 0.15.0", "libcnb-test", - "libherokubuildpack", + "libherokubuildpack 0.15.0", "serde", + "serde_json", "tempfile", + "test_support", "thiserror", - "toml", + "toml 0.8.1", "ureq", ] @@ -465,16 +605,20 @@ dependencies = [ name = "heroku-nodejs-function-invoker-buildpack" version = "0.0.0" dependencies = [ + "base64", "heroku-nodejs-utils", - "libcnb", + "hex", + "libcnb 0.15.0", "libcnb-test", - "libherokubuildpack", + "libherokubuildpack 0.15.0", + "rand", "serde", "serde_json", "tempfile", "test_support", "thiserror", - "toml", + "toml 0.8.1", + "ureq", ] [[package]] @@ -483,12 +627,12 @@ version = "0.0.0" dependencies = [ "heroku-nodejs-utils", "indoc", - "libcnb", + "libcnb 0.15.0", "libcnb-test", - "libherokubuildpack", + "libherokubuildpack 0.15.0", "serde", "test_support", - "toml", + "toml 0.8.1", "ureq", ] @@ -499,13 +643,16 @@ dependencies = [ "anyhow", "chrono", "node-semver", + "opentelemetry", + "opentelemetry-stdout", + "opentelemetry_sdk", "regex", "serde", "serde-xml-rs", "serde_json", "tempfile", "thiserror", - "toml", + "toml 0.8.1", "ureq", "url", ] @@ -515,14 +662,14 @@ name = "heroku-nodejs-yarn-buildpack" version = "0.0.0" dependencies = [ "heroku-nodejs-utils", - "libcnb", + "libcnb 0.15.0", "libcnb-test", - "libherokubuildpack", + "libherokubuildpack 0.15.0", "serde", "tempfile", "test_support", "thiserror", - "toml", + "toml 0.8.1", "ureq", ] @@ -533,14 +680,29 @@ dependencies = [ "commons", "heroku-nodejs-utils", "indoc", - "libcnb", + "libcnb 0.15.0", "libcnb-test", - "libherokubuildpack", + "libherokubuildpack 0.15.0", "serde", "serde_json", "tempfile", "test_support", - "toml", + "toml 0.8.1", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", ] [[package]] @@ -576,6 +738,23 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "ignore" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +dependencies = [ + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", +] + [[package]] name = "indexmap" version = "1.9.3" @@ -598,9 +777,9 @@ dependencies = [ [[package]] name = "indoc" -version = "2.0.3" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c785eefb63ebd0e33416dfcb8d6da0bf27ce752843a45632a67bf10d4d4b5c4" +checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" [[package]] name = "is_executable" @@ -643,9 +822,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libcnb" @@ -653,21 +832,36 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5132851c82d808e6b42edd1cc9e7cb9b16b0274c325b25fdb42660fae9b2e88b" dependencies = [ - "libcnb-data 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libcnb-proc-macros 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libcnb-data 0.14.0", + "libcnb-proc-macros 0.14.0", + "serde", + "thiserror", + "toml 0.7.8", +] + +[[package]] +name = "libcnb" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460e3b9d5b51eee9b9eb154e8bece15b77fff8b287457c09699a609c977003c9" +dependencies = [ + "libcnb-common", + "libcnb-data 0.15.0", + "libcnb-proc-macros 0.15.0", "serde", "thiserror", - "toml", + "toml 0.8.1", ] [[package]] name = "libcnb-common" -version = "0.14.0" -source = "git+https://github.com/heroku/libcnb.rs?branch=libcnb_test_meta_buildpack_support#bb714d98ad13537e1a9c79f03d7dbdf7ecb062d5" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c4c77089f294316c1d8a285d0ed9973e796a2653c676b22b3f7703d73aa828" dependencies = [ "serde", "thiserror", - "toml", + "toml 0.8.1", ] [[package]] @@ -677,34 +871,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bed8b0f2676aebeb216a7f7872151fbf74ff3706c7027449573c03c9d7f3393" dependencies = [ "fancy-regex", - "libcnb-proc-macros 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libcnb-proc-macros 0.14.0", "serde", "thiserror", - "toml", + "toml 0.7.8", "uriparse", ] [[package]] name = "libcnb-data" -version = "0.14.0" -source = "git+https://github.com/heroku/libcnb.rs?branch=libcnb_test_meta_buildpack_support#bb714d98ad13537e1a9c79f03d7dbdf7ecb062d5" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f35c4af3b47b67257263f0504897cf4db263b407b3e367971fc0b60ada69ce2" dependencies = [ "fancy-regex", - "libcnb-proc-macros 0.14.0 (git+https://github.com/heroku/libcnb.rs?branch=libcnb_test_meta_buildpack_support)", + "libcnb-proc-macros 0.15.0", "serde", "thiserror", - "toml", + "toml 0.8.1", "uriparse", ] [[package]] name = "libcnb-package" -version = "0.14.0" -source = "git+https://github.com/heroku/libcnb.rs?branch=libcnb_test_meta_buildpack_support#bb714d98ad13537e1a9c79f03d7dbdf7ecb062d5" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5ee4c1ac95fc5f71b0f8901d62644f9d39dad0be9d1a5bf23fae173aaf2a46c" dependencies = [ - "cargo_metadata", + "cargo_metadata 0.18.0", + "ignore", "libcnb-common", - "libcnb-data 0.14.0 (git+https://github.com/heroku/libcnb.rs?branch=libcnb_test_meta_buildpack_support)", + "libcnb-data 0.15.0", "petgraph", "thiserror", "uriparse", @@ -717,7 +914,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c715cec438b3a02c3564e9b9c20a78c54b9c71874249bec1e3d45fcd2537cfcf" dependencies = [ - "cargo_metadata", + "cargo_metadata 0.17.0", "fancy-regex", "quote", "syn", @@ -725,10 +922,11 @@ dependencies = [ [[package]] name = "libcnb-proc-macros" -version = "0.14.0" -source = "git+https://github.com/heroku/libcnb.rs?branch=libcnb_test_meta_buildpack_support#bb714d98ad13537e1a9c79f03d7dbdf7ecb062d5" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5effc8c71a7401899ea2885681b213b779449dc0f581663ea850d9de0718434c" dependencies = [ - "cargo_metadata", + "cargo_metadata 0.18.0", "fancy-regex", "quote", "syn", @@ -736,13 +934,14 @@ dependencies = [ [[package]] name = "libcnb-test" -version = "0.14.0" -source = "git+https://github.com/heroku/libcnb.rs?branch=libcnb_test_meta_buildpack_support#bb714d98ad13537e1a9c79f03d7dbdf7ecb062d5" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b88d0682a1abd6261f406f52214272c09738ddae239cc5d38159dfa7a53e2e63" dependencies = [ "fastrand", "fs_extra", "libcnb-common", - "libcnb-data 0.14.0 (git+https://github.com/heroku/libcnb.rs?branch=libcnb_test_meta_buildpack_support)", + "libcnb-data 0.15.0", "libcnb-package", "tempfile", ] @@ -755,13 +954,31 @@ checksum = "999689d1a9f8cbea478ae7c4ce6136601e7abe9512ccfc0409f5525949a41457" dependencies = [ "crossbeam-utils", "flate2", - "libcnb", + "libcnb 0.14.0", "pathdiff", "sha2", "tar", "termcolor", "thiserror", - "toml", + "toml 0.7.8", + "ureq", +] + +[[package]] +name = "libherokubuildpack" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c01b437767257854de9a8011c6f7e265dc6ebc344cc122ffef2464f3e10bfc8" +dependencies = [ + "crossbeam-utils", + "flate2", + "libcnb 0.15.0", + "pathdiff", + "sha2", + "tar", + "termcolor", + "thiserror", + "toml 0.8.1", "ureq", ] @@ -778,9 +995,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" [[package]] name = "log" @@ -790,9 +1007,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "memoffset" @@ -874,20 +1091,69 @@ dependencies = [ ] [[package]] -name = "num_cpus" -version = "1.16.0" +name = "once_cell" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "opentelemetry" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9591d937bc0e6d2feb6f71a559540ab300ea49955229c347a517a28d27784c54" dependencies = [ - "hermit-abi", - "libc", + "opentelemetry_api", + "opentelemetry_sdk", ] [[package]] -name = "once_cell" -version = "1.18.0" +name = "opentelemetry-stdout" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "8bd550321bc0f9d3f6dcbfe5c75262789de5b3e2776da2cbcfd2392aa05db0c6" +dependencies = [ + "futures-util", + "opentelemetry_api", + "opentelemetry_sdk", + "ordered-float", + "serde", + "serde_json", +] + +[[package]] +name = "opentelemetry_api" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a81f725323db1b1206ca3da8bb19874bbd3f57c3bcd59471bfb04525b265b9b" +dependencies = [ + "futures-channel", + "futures-util", + "indexmap 1.9.3", + "js-sys", + "once_cell", + "pin-project-lite", + "thiserror", + "urlencoding", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa8e705a0612d48139799fcbaba0d4a90f06277153e43dd2bdc16c6f0edd8026" +dependencies = [ + "async-trait", + "crossbeam-channel", + "futures-channel", + "futures-executor", + "futures-util", + "once_cell", + "opentelemetry_api", + "ordered-float", + "percent-encoding", + "rand", + "thiserror", +] [[package]] name = "ordered-float" @@ -912,25 +1178,43 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "petgraph" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 1.9.3", + "indexmap 2.0.0", ] +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "pkg-config" version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] @@ -944,11 +1228,41 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "rayon" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" dependencies = [ "either", "rayon-core", @@ -956,14 +1270,12 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] @@ -977,9 +1289,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.4" +version = "1.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" +checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" dependencies = [ "aho-corasick", "memchr", @@ -989,9 +1301,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" dependencies = [ "aho-corasick", "memchr", @@ -1021,9 +1333,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.8" +version = "0.38.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" dependencies = [ "bitflags 2.4.0", "errno", @@ -1040,20 +1352,10 @@ checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" dependencies = [ "log", "ring", - "rustls-webpki 0.101.3", + "rustls-webpki", "sct", ] -[[package]] -name = "rustls-webpki" -version = "0.100.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "rustls-webpki" version = "0.101.3" @@ -1138,9 +1440,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.105" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", @@ -1167,6 +1469,15 @@ dependencies = [ "digest", ] +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "spin" version = "0.5.2" @@ -1181,9 +1492,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "2.0.29" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2", "quote", @@ -1215,9 +1526,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" dependencies = [ "winapi-util", ] @@ -1226,26 +1537,27 @@ dependencies = [ name = "test_support" version = "0.0.0" dependencies = [ - "libcnb-data 0.14.0 (git+https://github.com/heroku/libcnb.rs?branch=libcnb_test_meta_buildpack_support)", + "libcnb 0.15.0", "libcnb-test", + "serde_json", "tempfile", "ureq", ] [[package]] name = "thiserror" -version = "1.0.47" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.47" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", @@ -1253,14 +1565,13 @@ dependencies = [ ] [[package]] -name = "time" -version = "0.1.45" +name = "thread_local" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ - "libc", - "wasi", - "winapi", + "cfg-if", + "once_cell", ] [[package]] @@ -1280,14 +1591,26 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toml" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.19.15", +] + +[[package]] +name = "toml" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc1433177506450fe920e46a4f9812d0c211f5dd556da10e731a0a3dfa151f0" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.20.1", ] [[package]] @@ -1301,9 +1624,22 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.0.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "ca676d9ba1a322c1b64eb8045a5ec5c0cfb0c9d08e15e9ff622589ad5221c8fe" dependencies = [ "indexmap 2.0.0", "serde", @@ -1345,6 +1681,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "untrusted" version = "0.7.1" @@ -1353,16 +1695,16 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "ureq" -version = "2.7.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b11c96ac7ee530603dcdf68ed1557050f374ce55a5a07193ebf8cbc9f8927e9" +checksum = "f5ccd538d4a604753ebc2f17cd9946e89b77bf87f6a8e2309667c6f2e87855e3" dependencies = [ "base64", "flate2", "log", "once_cell", "rustls", - "rustls-webpki 0.100.1", + "rustls-webpki", "serde", "serde_json", "url", @@ -1390,6 +1732,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf8-width" version = "0.1.6" @@ -1420,9 +1768,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" @@ -1490,22 +1838,20 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.23.1" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" -dependencies = [ - "rustls-webpki 0.100.1", -] +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" [[package]] name = "which" -version = "4.4.0" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" dependencies = [ "either", - "libc", + "home", "once_cell", + "rustix", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 840e951e..01a940d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,16 +22,16 @@ heroku-nodejs-utils = { path = "./common/nodejs-utils" } indoc = "2" # libcnb has a much bigger impact on buildpack behaviour than any other dependencies, # so it's pinned to an exact version to isolate it from lockfile refreshes. -libcnb-test = { git = "https://github.com/heroku/libcnb.rs", branch = "libcnb_test_meta_buildpack_support" } -libcnb = "=0.14.0" -libcnb-data = { git = "https://github.com/heroku/libcnb.rs", branch = "libcnb_test_meta_buildpack_support" } -libherokubuildpack = "=0.14.0" +libcnb-test = "=0.15.0" +libcnb = "=0.15.0" +libherokubuildpack = "=0.15.0" +opentelemetry = "0.20.0" serde = "1" serde_json = "1" test_support = { path = "./test_support" } tempfile = "3" thiserror = "1" -toml = "0.7" +toml = "0.8" ureq = "2" [profile.release] diff --git a/Gemfile b/Gemfile deleted file mode 100644 index aa2e2175..00000000 --- a/Gemfile +++ /dev/null @@ -1,8 +0,0 @@ -source "https://rubygems.org" - -gem 'rspec-retry' -gem 'rspec-expectations' -gem 'java-properties' -gem 'dead_end' -gem 'cutlass' -gem 'parallel_split_test' diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index e3c78354..00000000 --- a/Gemfile.lock +++ /dev/null @@ -1,41 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - cutlass (0.3.0) - docker-api (>= 2.0) - dead_end (4.0.0) - diff-lcs (1.5.0) - docker-api (2.2.0) - excon (>= 0.47.0) - multi_json - excon (0.87.0) - java-properties (0.3.0) - multi_json (1.15.0) - parallel (1.20.1) - parallel_split_test (0.10.0) - parallel (>= 0.5.13) - rspec-core (>= 3.9.0) - rspec-core (3.12.0) - rspec-support (~> 3.12.0) - rspec-expectations (3.12.3) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.12.0) - rspec-retry (0.6.2) - rspec-core (> 3.3) - rspec-support (3.12.0) - -PLATFORMS - ruby - x86_64-darwin-19 - x86_64-linux - -DEPENDENCIES - cutlass - dead_end - java-properties - parallel_split_test - rspec-expectations - rspec-retry - -BUNDLED WITH - 2.2.22 diff --git a/README.md b/README.md index 61b42467..9072218a 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,6 @@ please see [heroku/nodejs](https://github.com/heroku/heroku-buildpack-nodejs). - [`jq`](https://github.com/stedolan/jq) >= `1.6` - [`shpec`](https://github.com/rylnd/shpec) -#### For cutlass integration tests -- `Ruby` >= `2.7` -- `bundler` via `gem install bundler` - ### Building 1. Run `cargo install libcnb-cargo` to [install the `libcnb` Cargo command](https://github.com/heroku/libcnb.rs#libcnb-cargo-command) @@ -56,9 +52,8 @@ pack build example-app \ ### Testing -- `cargo test` performs Rust unit and intgration tests for the `heroku/nodejs-engine` buildpack. -- `bundle exec rspec test/specs/node` runs cutlass integration tests for the `heroku/nodejs` buildpack. -- `bundle exec rspec test/specs/node-function` runs cutlass integration tests for the `heroku/nodejs-function` buildpack. +- `cargo test` runs Rust unit tests. +- `cargo test -- --ignored` runs Rust integration tests. - `shpec buildpacks/npm/shpec/*_shpec.sh` runs the shpec unit tests for the `heroku/nodejs-npm` buildpack. - `shpec buildpacks/nodejs-function-invoker/shpec/*_shpec.sh` runs the shpec unit tests for the `heroku/nodejs-function-invoker` buildpack. diff --git a/buildpacks/nodejs-corepack/CHANGELOG.md b/buildpacks/nodejs-corepack/CHANGELOG.md index 732f4295..b1454d34 100644 --- a/buildpacks/nodejs-corepack/CHANGELOG.md +++ b/buildpacks/nodejs-corepack/CHANGELOG.md @@ -2,11 +2,19 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [1.1.6] - 2023-09-25 + +- Add basic OpenTelemetry tracing. ([#652](https://github.com/heroku/buildpacks-nodejs/pull/652)) + +## [1.1.5] - 2023-09-19 + +- No changes. + ## [1.1.4] - 2023-08-10 - No changes. @@ -40,9 +48,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Initial implementation with libcnb.rs ([#418](https://github.com/heroku/buildpacks-nodejs/pull/418)) -[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...HEAD +[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.6...HEAD +[1.1.6]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.5...v1.1.6 +[1.1.5]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...v1.1.5 [1.1.4]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.3...v1.1.4 [1.1.3]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.2...v1.1.3 [1.1.2]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.1...v1.1.2 [1.1.1]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.0...v1.1.1 -[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 \ No newline at end of file +[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 diff --git a/buildpacks/nodejs-corepack/Cargo.toml b/buildpacks/nodejs-corepack/Cargo.toml index 51e81401..6815a331 100644 --- a/buildpacks/nodejs-corepack/Cargo.toml +++ b/buildpacks/nodejs-corepack/Cargo.toml @@ -10,6 +10,7 @@ publish.workspace = true heroku-nodejs-utils.workspace = true libcnb.workspace = true libherokubuildpack.workspace = true +opentelemetry.workspace = true serde.workspace = true thiserror.workspace = true indoc.workspace = true diff --git a/buildpacks/nodejs-corepack/README.md b/buildpacks/nodejs-corepack/README.md index a06869e0..829eacc0 100644 --- a/buildpacks/nodejs-corepack/README.md +++ b/buildpacks/nodejs-corepack/README.md @@ -56,7 +56,7 @@ manager is installed. ## Usage For most users, it's simplest to build an app using [`pack`](https://buildpacks.io/docs/tools/pack/) -and Heroku's [builder](https://github.com/builder), which includes this buildpack. +and Heroku's [builder](https://github.com/heroku/cnb-builder-images), which includes this buildpack. ``` pack build example-app-image --builder heroku/builder:22 --path /my/example-app diff --git a/buildpacks/nodejs-corepack/buildpack.toml b/buildpacks/nodejs-corepack/buildpack.toml index 8afd8846..c9470b0b 100644 --- a/buildpacks/nodejs-corepack/buildpack.toml +++ b/buildpacks/nodejs-corepack/buildpack.toml @@ -2,7 +2,7 @@ api = "0.9" [buildpack] id = "heroku/nodejs-corepack" -version = "1.1.4" +version = "1.1.6" name = "Heroku Node.js Corepack" homepage = "https://github.com/heroku/buildpacks-nodejs" keywords = ["corepack", "node", "node.js", "nodejs", "javascript", "js"] diff --git a/buildpacks/nodejs-corepack/src/main.rs b/buildpacks/nodejs-corepack/src/main.rs index d5dc0b38..1fc8afc6 100644 --- a/buildpacks/nodejs-corepack/src/main.rs +++ b/buildpacks/nodejs-corepack/src/main.rs @@ -4,6 +4,7 @@ #![allow(clippy::module_name_repetitions)] use heroku_nodejs_utils::package_json::{PackageJson, PackageJsonError}; +use heroku_nodejs_utils::telemetry::init_tracer; use layers::{ManagerLayer, ShimLayer}; use libcnb::build::{BuildContext, BuildResult, BuildResultBuilder}; use libcnb::data::build_plan::BuildPlanBuilder; @@ -14,6 +15,8 @@ use libcnb::generic::GenericPlatform; use libcnb::layer_env::Scope; use libcnb::{buildpack_main, Buildpack, Env}; use libherokubuildpack::log::log_header; +use opentelemetry::trace::{TraceContextExt, Tracer}; +use opentelemetry::KeyValue; #[cfg(test)] use libcnb_test as _; @@ -35,62 +38,78 @@ impl Buildpack for CorepackBuildpack { type Error = CorepackBuildpackError; fn detect(&self, context: DetectContext) -> libcnb::Result { - // Corepack requires the `packageManager` key from `package.json`. - // This buildpack won't be detected without it. - let pkg_json_path = context.app_dir.join("package.json"); - if pkg_json_path.exists() { - let pkg_json = - PackageJson::read(pkg_json_path).map_err(CorepackBuildpackError::PackageJson)?; - cfg::get_supported_package_manager(&pkg_json).map_or_else( - || DetectResultBuilder::fail().build(), - |pkg_mgr| { - DetectResultBuilder::pass() - .build_plan( - BuildPlanBuilder::new() - .requires("node") - .requires(&pkg_mgr) - .provides(pkg_mgr) - .build(), - ) - .build() - }, - ) - } else { - DetectResultBuilder::fail().build() - } + let tracer = init_tracer(context.buildpack_descriptor.buildpack.id.to_string()); + tracer.in_span("nodejs-corepack-detect", |_cx| { + // Corepack requires the `packageManager` key from `package.json`. + // This buildpack won't be detected without it. + let pkg_json_path = context.app_dir.join("package.json"); + if pkg_json_path.exists() { + let pkg_json = PackageJson::read(pkg_json_path) + .map_err(CorepackBuildpackError::PackageJson)?; + cfg::get_supported_package_manager(&pkg_json).map_or_else( + || DetectResultBuilder::fail().build(), + |pkg_mgr| { + DetectResultBuilder::pass() + .build_plan( + BuildPlanBuilder::new() + .requires("node") + .requires(&pkg_mgr) + .provides(pkg_mgr) + .build(), + ) + .build() + }, + ) + } else { + DetectResultBuilder::fail().build() + } + }) } fn build(&self, context: BuildContext) -> libcnb::Result { - let pkg_mgr = PackageJson::read(context.app_dir.join("package.json")) - .map_err(CorepackBuildpackError::PackageJson)? - .package_manager - .ok_or(CorepackBuildpackError::PackageManagerMissing)?; - - let env = &Env::from_current(); - - let corepack_version = - cmd::corepack_version(env).map_err(CorepackBuildpackError::CorepackVersion)?; - - log_header(format!( - "Installing {} {} via corepack {corepack_version}", - pkg_mgr.name, pkg_mgr.version - )); - - let shims_layer = - context.handle_layer(layer_name!("shim"), ShimLayer { corepack_version })?; - cmd::corepack_enable(&pkg_mgr.name, &shims_layer.path.join("bin"), env) - .map_err(CorepackBuildpackError::CorepackEnable)?; - - let mgr_layer = context.handle_layer( - layer_name!("mgr"), - ManagerLayer { - package_manager: pkg_mgr, - }, - )?; - let mgr_env = mgr_layer.env.apply(Scope::Build, env); - cmd::corepack_prepare(&mgr_env).map_err(CorepackBuildpackError::CorepackPrepare)?; - - BuildResultBuilder::new().build() + let tracer = init_tracer(context.buildpack_descriptor.buildpack.id.to_string()); + tracer.in_span("nodejs-corepack-build", |cx| { + let pkg_mgr = PackageJson::read(context.app_dir.join("package.json")) + .map_err(CorepackBuildpackError::PackageJson)? + .package_manager + .ok_or(CorepackBuildpackError::PackageManagerMissing)?; + + cx.span().set_attributes([ + KeyValue::new("package_manager.name", pkg_mgr.name.clone()), + KeyValue::new("package_manager.version", pkg_mgr.version.to_string()), + ]); + + let env = &Env::from_current(); + + let corepack_version = + cmd::corepack_version(env).map_err(CorepackBuildpackError::CorepackVersion)?; + + cx.span().set_attribute(KeyValue::new( + "corepack.version", + corepack_version.to_string(), + )); + + log_header(format!( + "Installing {} {} via corepack {corepack_version}", + pkg_mgr.name, pkg_mgr.version + )); + + let shims_layer = + context.handle_layer(layer_name!("shim"), ShimLayer { corepack_version })?; + cmd::corepack_enable(&pkg_mgr.name, &shims_layer.path.join("bin"), env) + .map_err(CorepackBuildpackError::CorepackEnable)?; + + let mgr_layer = context.handle_layer( + layer_name!("mgr"), + ManagerLayer { + package_manager: pkg_mgr, + }, + )?; + let mgr_env = mgr_layer.env.apply(Scope::Build, env); + cmd::corepack_prepare(&mgr_env).map_err(CorepackBuildpackError::CorepackPrepare)?; + + BuildResultBuilder::new().build() + }) } fn on_error(&self, err: libcnb::Error) { diff --git a/buildpacks/nodejs-corepack/tests/integration_test.rs b/buildpacks/nodejs-corepack/tests/integration_test.rs index cd6b6f10..69886372 100644 --- a/buildpacks/nodejs-corepack/tests/integration_test.rs +++ b/buildpacks/nodejs-corepack/tests/integration_test.rs @@ -1,13 +1,12 @@ #![warn(clippy::pedantic)] use libcnb_test::assert_contains; -use test_support::test_corepack_app; -use test_support::Builder::{Heroku20, Heroku22}; +use test_support::nodejs_integration_test; #[test] #[ignore = "integration test"] -fn corepack_yarn_2_heroku_20() { - test_corepack_app("yarn-2-pnp-zero", Heroku20, |ctx| { +fn corepack_yarn_2() { + nodejs_integration_test("../../../test/fixtures/yarn-2-pnp-zero", |ctx| { assert_contains!(ctx.pack_stdout, "Preparing yarn@2.4.1"); let output = ctx.run_shell_command("yarn --version"); assert_contains!(output.stdout, "2.4.1"); @@ -16,8 +15,8 @@ fn corepack_yarn_2_heroku_20() { #[test] #[ignore = "integration test"] -fn corepack_yarn_3_heroku_22() { - test_corepack_app("yarn-3-pnp-nonzero", Heroku22, |ctx| { +fn corepack_yarn_3() { + nodejs_integration_test("../../../test/fixtures/yarn-3-pnp-nonzero", |ctx| { assert_contains!(ctx.pack_stdout, "Preparing yarn@3.2.0"); let output = ctx.run_shell_command("yarn --version"); assert_contains!(output.stdout, "3.2.0"); @@ -27,7 +26,7 @@ fn corepack_yarn_3_heroku_22() { #[test] #[ignore = "integration test"] fn corepack_pnpm_7() { - test_corepack_app("pnpm-7-pnp", Heroku20, |ctx| { + nodejs_integration_test("../../../test/fixtures/pnpm-7-pnp", |ctx| { assert_contains!(ctx.pack_stdout, "Preparing pnpm@7.32.3"); let output = ctx.run_shell_command("pnpm --version"); assert_contains!(output.stdout, "7.32.3"); @@ -37,7 +36,7 @@ fn corepack_pnpm_7() { #[test] #[ignore = "integration test"] fn corepack_pnpm_8() { - test_corepack_app("pnpm-8-hoist", Heroku22, |ctx| { + nodejs_integration_test("../../../test/fixtures/pnpm-8-hoist", |ctx| { assert_contains!(ctx.pack_stdout, "Preparing pnpm@8.4.0"); let output = ctx.run_shell_command("pnpm --version"); assert_contains!(output.stdout, "8.4.0"); diff --git a/buildpacks/nodejs-engine/CHANGELOG.md b/buildpacks/nodejs-engine/CHANGELOG.md index cd306b1e..4da7ab22 100644 --- a/buildpacks/nodejs-engine/CHANGELOG.md +++ b/buildpacks/nodejs-engine/CHANGELOG.md @@ -2,11 +2,25 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +- Added Node.js version 20.8.0. +- Provides `npm` added to the build plan since a default version of `npm` is bundled with Node.js. ([#622](https://github.com/heroku/buildpacks-nodejs/pull/622)) + +## [1.1.6] - 2023-09-25 + +- No changes. + +## [1.1.5] - 2023-09-19 + +- Added Node.js version 20.7.0. +- Added Node.js version 18.18.0. +- Added Node.js version 20.6.1. +- Added Node.js version 20.6.0. + ## [1.1.4] - 2023-08-10 - Added Node.js version 16.20.2. @@ -241,9 +255,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Parse engines and add them to nodejs.toml ([#25](https://github.com/heroku/nodejs-engine-buildpack/pull/25)) - Add shellcheck to test suite ([#24](https://github.com/heroku/nodejs-engine-buildpack/pull/24)) -[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...HEAD +[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.6...HEAD +[1.1.6]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.5...v1.1.6 +[1.1.5]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...v1.1.5 [1.1.4]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.3...v1.1.4 [1.1.3]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.2...v1.1.3 [1.1.2]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.1...v1.1.2 [1.1.1]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.0...v1.1.1 -[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 \ No newline at end of file +[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 diff --git a/buildpacks/nodejs-engine/Cargo.toml b/buildpacks/nodejs-engine/Cargo.toml index 054d1c3f..f1864951 100644 --- a/buildpacks/nodejs-engine/Cargo.toml +++ b/buildpacks/nodejs-engine/Cargo.toml @@ -17,4 +17,6 @@ thiserror.workspace = true [dev-dependencies] libcnb-test.workspace = true +test_support.workspace = true +serde_json.workspace = true ureq.workspace = true diff --git a/buildpacks/nodejs-engine/buildpack.toml b/buildpacks/nodejs-engine/buildpack.toml index 2927a0f0..4b44ebdb 100644 --- a/buildpacks/nodejs-engine/buildpack.toml +++ b/buildpacks/nodejs-engine/buildpack.toml @@ -2,7 +2,7 @@ api = "0.9" [buildpack] id = "heroku/nodejs-engine" -version = "1.1.4" +version = "1.1.6" name = "Heroku Node.js Engine" homepage = "https://github.com/heroku/buildpacks-nodejs" keywords = ["node", "node.js", "nodejs", "javascript", "js"] diff --git a/buildpacks/nodejs-engine/inventory.toml b/buildpacks/nodejs-engine/inventory.toml index 874b7041..88b7137c 100644 --- a/buildpacks/nodejs-engine/inventory.toml +++ b/buildpacks/nodejs-engine/inventory.toml @@ -5397,6 +5397,13 @@ arch = "linux-x64" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/node/release/linux-x64/node-v18.17.1-linux-x64.tar.gz" etag = "40bed92d4aebcdbb9cee979e1f03859e-6" +[[releases]] +version = "18.18.0" +channel = "release" +arch = "linux-x64" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/node/release/linux-x64/node-v18.18.0-linux-x64.tar.gz" +etag = "6786cf20445987a3db61fe4d032d1f56-6" + [[releases]] version = "18.2.0" channel = "release" @@ -5607,6 +5614,34 @@ arch = "linux-x64" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/node/release/linux-x64/node-v20.5.1-linux-x64.tar.gz" etag = "f3de44a4f1ce4a000f2119dbfe66c54e-6" +[[releases]] +version = "20.6.0" +channel = "release" +arch = "linux-x64" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/node/release/linux-x64/node-v20.6.0-linux-x64.tar.gz" +etag = "ae54a8c0c43e65a0d6656a8c58b17128-6" + +[[releases]] +version = "20.6.1" +channel = "release" +arch = "linux-x64" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/node/release/linux-x64/node-v20.6.1-linux-x64.tar.gz" +etag = "31337a8bf7b975a112c982cb59634fb6-6" + +[[releases]] +version = "20.7.0" +channel = "release" +arch = "linux-x64" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/node/release/linux-x64/node-v20.7.0-linux-x64.tar.gz" +etag = "e0f1b651dcf0db279846ccfab09321dc-6" + +[[releases]] +version = "20.8.0" +channel = "release" +arch = "linux-x64" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/node/release/linux-x64/node-v20.8.0-linux-x64.tar.gz" +etag = "537d2c2b3f13e969b67e61e4f8ed8a0f-6" + [[releases]] version = "4.0.0" channel = "release" diff --git a/buildpacks/nodejs-engine/src/main.rs b/buildpacks/nodejs-engine/src/main.rs index 48945627..ef80aa1f 100644 --- a/buildpacks/nodejs-engine/src/main.rs +++ b/buildpacks/nodejs-engine/src/main.rs @@ -15,17 +15,19 @@ use libcnb::detect::{DetectContext, DetectResult, DetectResultBuilder}; use libcnb::generic::GenericMetadata; use libcnb::generic::GenericPlatform; use libcnb::{buildpack_main, Buildpack}; -use libherokubuildpack::log::{log_error, log_header, log_info}; -use thiserror::Error; - -mod layers; - #[cfg(test)] use libcnb_test as _; - +use libherokubuildpack::log::{log_error, log_header, log_info}; +#[cfg(test)] +use serde_json as _; +#[cfg(test)] +use test_support as _; +use thiserror::Error; #[cfg(test)] use ureq as _; +mod layers; + const INVENTORY: &str = include_str!("../inventory.toml"); pub struct NodeJsEngineBuildpack; diff --git a/buildpacks/nodejs-engine/tests/integration_test.rs b/buildpacks/nodejs-engine/tests/integration_test.rs index 6d34dcfa..f962dd24 100644 --- a/buildpacks/nodejs-engine/tests/integration_test.rs +++ b/buildpacks/nodejs-engine/tests/integration_test.rs @@ -1,99 +1,83 @@ #![warn(clippy::pedantic)] -use libcnb_test::{assert_contains, BuildConfig, ContainerConfig, ContainerContext, TestRunner}; -use std::time::Duration; - -const PORT: u16 = 8080; - -fn test_node(fixture: &str, builder: &str, expect_lines: &[&str]) { - TestRunner::default().build( - BuildConfig::new(builder, format!("../../test/fixtures/{fixture}")), - |ctx| { - for expect_line in expect_lines { - assert_contains!(ctx.pack_stdout, expect_line); - } - ctx.start_container(ContainerConfig::new().expose_port(PORT), |container| { - test_response(&container, fixture); - }); - }, - ); -} - -fn test_response(container: &ContainerContext, text: &str) { - std::thread::sleep(Duration::from_secs(5)); - let addr = container.address_for_port(PORT); - let resp = ureq::get(&format!("http://{addr}")) - .call() - .expect("request to container failed") - .into_string() - .expect("response read error"); - - assert_contains!(resp, text); -} +use libcnb_test::{assert_contains, assert_not_contains}; +use test_support::{ + assert_web_response, nodejs_integration_test, nodejs_integration_test_with_config, + set_node_engine, +}; #[test] #[ignore] -fn simple_indexjs_heroku20() { - test_node( - "node-with-indexjs", - "heroku/buildpacks:20", - &["Detected Node.js version range: *", "Installing Node.js"], - ); +fn simple_indexjs() { + nodejs_integration_test("../../../test/fixtures/node-with-indexjs", |ctx| { + assert_contains!(ctx.pack_stdout, "Detected Node.js version range: *"); + assert_contains!(ctx.pack_stdout, "Installing Node.js"); + assert_web_response(&ctx, "node-with-indexjs"); + }); } #[test] #[ignore] -fn simple_indexjs_heroku22() { - test_node( - "node-with-indexjs", - "heroku/builder:22", - &["Detected Node.js version range: *", "Installing Node.js"], - ); +fn simple_serverjs() { + nodejs_integration_test("../../../test/fixtures/node-with-serverjs", |ctx| { + assert_contains!(ctx.pack_stdout, "Installing Node.js 16.0.0"); + assert_web_response(&ctx, "node-with-serverjs"); + }); } #[test] #[ignore] -fn simple_serverjs_heroku20() { - test_node( - "node-with-serverjs", - "heroku/buildpacks:20", - &["Installing Node.js 16.0.0"], +fn reinstalls_node_if_version_changes() { + nodejs_integration_test_with_config( + "../../../test/fixtures/node-with-indexjs", + |config| { + config.app_dir_preprocessor(|app_dir| { + set_node_engine(&app_dir, "^14.0"); + }); + }, + |ctx| { + assert_contains!(ctx.pack_stdout, "Installing Node.js 14"); + let mut config = ctx.config.clone(); + config.app_dir_preprocessor(|app_dir| { + set_node_engine(&app_dir, "^16.0"); + }); + ctx.rebuild(config, |ctx| { + assert_contains!(ctx.pack_stdout, "Installing Node.js 16"); + }); + }, ); } +// TODO: move this test & fixture to the npm buildpack once that is ready #[test] #[ignore] -fn simple_serverjs_heroku22() { - test_node( - "node-with-serverjs", - "heroku/builder:22", - &["Installing Node.js 16.0.0"], - ); +fn npm_project_with_no_lockfile() { + nodejs_integration_test("../../../test/fixtures/npm-project", |ctx| { + assert_contains!(ctx.pack_stdout, "Installing Node"); + assert_contains!(ctx.pack_stdout, "Installing node modules"); + + assert_not_contains!(ctx.pack_stdout, "Installing yarn"); + assert_not_contains!(ctx.pack_stdout, "Installing node modules from ./yarn.lock"); + assert_not_contains!( + ctx.pack_stdout, + "Installing node modules from ./package-lock.json" + ); + }); } +// TODO: move this test & fixture to the npm buildpack once that is ready #[test] #[ignore] -fn upgrade_simple_indexjs_from_heroku20_to_heroku22() { - TestRunner::default().build( - BuildConfig::new( - "heroku/buildpacks:20", - "../../test/fixtures/node-with-indexjs", - ), - |initial_ctx| { - assert_contains!(initial_ctx.pack_stdout, "Installing Node.js"); - initial_ctx.rebuild( - BuildConfig::new("heroku/builder:22", "../../test/fixtures/node-with-indexjs"), - |upgrade_ctx| { - assert_contains!(upgrade_ctx.pack_stdout, "Installing Node.js"); - let port = 8080; - upgrade_ctx.start_container( - ContainerConfig::new().expose_port(port), - |container| { - test_response(&container, "node-with-index"); - }, - ); - }, - ); - }, - ); +fn npm_project_with_lockfile() { + nodejs_integration_test("../../../test/fixtures/npm-project-with-lockfile", |ctx| { + assert_contains!(ctx.pack_stdout, "Installing Node"); + assert_contains!(ctx.pack_stdout, "Installing node modules"); + assert_contains!( + ctx.pack_stdout, + "Installing node modules from ./package-lock.json" + ); + + assert_not_contains!(ctx.pack_stdout, "Installing yarn"); + assert_not_contains!(ctx.pack_stdout, "Installing node modules from ./yarn.lock"); + }); } diff --git a/buildpacks/nodejs-function-invoker/CHANGELOG.md b/buildpacks/nodejs-function-invoker/CHANGELOG.md index 30a498c2..370d9783 100644 --- a/buildpacks/nodejs-function-invoker/CHANGELOG.md +++ b/buildpacks/nodejs-function-invoker/CHANGELOG.md @@ -2,11 +2,19 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [1.1.6] - 2023-09-25 + +- No changes. + +## [1.1.5] - 2023-09-19 + +- No changes. + ## [1.1.4] - 2023-08-10 - No changes. @@ -175,9 +183,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Initial implementation ([#47](https://github.com/heroku/buildpacks-node/pull/47)) -[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...HEAD +[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.6...HEAD +[1.1.6]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.5...v1.1.6 +[1.1.5]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...v1.1.5 [1.1.4]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.3...v1.1.4 [1.1.3]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.2...v1.1.3 [1.1.2]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.1...v1.1.2 [1.1.1]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.0...v1.1.1 -[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 \ No newline at end of file +[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 diff --git a/buildpacks/nodejs-function-invoker/Cargo.toml b/buildpacks/nodejs-function-invoker/Cargo.toml index 6a72dfb2..b0ce87ed 100644 --- a/buildpacks/nodejs-function-invoker/Cargo.toml +++ b/buildpacks/nodejs-function-invoker/Cargo.toml @@ -15,7 +15,11 @@ thiserror.workspace = true toml.workspace = true [dev-dependencies] +base64 = "0.21" +hex = "0.4" libcnb-test.workspace = true +rand = "0.8" serde_json.workspace = true tempfile.workspace = true test_support.workspace = true +ureq.workspace = true diff --git a/buildpacks/nodejs-function-invoker/buildpack.toml b/buildpacks/nodejs-function-invoker/buildpack.toml index ec0f3ec6..c181c758 100644 --- a/buildpacks/nodejs-function-invoker/buildpack.toml +++ b/buildpacks/nodejs-function-invoker/buildpack.toml @@ -2,7 +2,7 @@ api = "0.9" [buildpack] id = "heroku/nodejs-function-invoker" -version = "1.1.4" +version = "1.1.6" name = "Heroku Node.js Function Invoker" homepage = "https://github.com/heroku/buildpacks-nodejs" keywords = ["nodejs", "node", "node.js", "javascript", "js", "function"] diff --git a/buildpacks/nodejs-function-invoker/src/main.rs b/buildpacks/nodejs-function-invoker/src/main.rs index 77799b99..3d5bd40d 100644 --- a/buildpacks/nodejs-function-invoker/src/main.rs +++ b/buildpacks/nodejs-function-invoker/src/main.rs @@ -10,6 +10,10 @@ use crate::function::{ use crate::layers::{ RuntimeLayer, RuntimeLayerError, ScriptLayer, ScriptLayerError, NODEJS_RUNTIME_SCRIPT, }; +#[cfg(test)] +use base64 as _; +#[cfg(test)] +use hex as _; use libcnb::build::{BuildContext, BuildResult, BuildResultBuilder}; use libcnb::data::build_plan::BuildPlanBuilder; use libcnb::data::launch::{LaunchBuilder, ProcessBuilder}; @@ -21,10 +25,14 @@ use libcnb::{buildpack_main, Buildpack}; use libcnb_test as _; use libherokubuildpack::error::on_error; use libherokubuildpack::log::{log_error, log_header, log_info, log_warning}; +#[cfg(test)] +use rand as _; use serde::Deserialize; #[cfg(test)] use test_support as _; use thiserror::Error; +#[cfg(test)] +use ureq as _; mod function; mod layers; diff --git a/buildpacks/nodejs-function-invoker/tests/integration_test.rs b/buildpacks/nodejs-function-invoker/tests/integration_test.rs index d7a22d10..d51c5dcd 100644 --- a/buildpacks/nodejs-function-invoker/tests/integration_test.rs +++ b/buildpacks/nodejs-function-invoker/tests/integration_test.rs @@ -1,89 +1,178 @@ #![warn(clippy::pedantic)] -use libcnb_test::{assert_contains, assert_not_contains}; -use test_support::Builder::Heroku22; -use test_support::{assert_health_check_responds, test_node_function}; +use base64::Engine; +use libcnb_test::{assert_contains, assert_not_contains, TestContext}; +use rand::RngCore; +use std::net::SocketAddr; +use test_support::{ + function_integration_test, retry, start_container, DEFAULT_RETRIES, DEFAULT_RETRY_DELAY, +}; #[test] #[ignore] -fn simple_javascript_function_heroku_22() { - test_node_function("simple-function", Heroku22, |ctx| { - assert_health_check_responds(&ctx); +fn simple_javascript_function() { + function_integration_test("../../../test/fixtures/simple-function", |ctx| { + assert_contains!(ctx.pack_stdout, "Installing Node.js Function Invoker"); + start_container(&ctx, |container, socket_addr| { + assert_health_check_responds(socket_addr); + let payload = serde_json::json!({}); + let result = invoke_function(socket_addr, &payload); + assert_eq!(result, serde_json::Value::String("hello world".to_string())); + let container_logs = container.logs_now(); + assert_contains!(container_logs.stdout, "logging info is a fun 1"); + }); }); } #[test] #[ignore] -fn simple_typescript_function_heroku_22() { - test_node_function("simple-typescript-function", Heroku22, |ctx| { - assert_health_check_responds(&ctx); +fn simple_typescript_function() { + function_integration_test("../../../test/fixtures/simple-typescript-function", |ctx| { + assert_contains!(ctx.pack_stdout, "Installing Node.js Function Invoker"); + start_container(&ctx, |_container, socket_addr| { + assert_health_check_responds(socket_addr); + let payload = serde_json::json!({}); + let result = invoke_function(socket_addr, &payload); + assert_eq!( + result, + serde_json::Value::String("hello world from typescript".to_string()) + ); + }); }); } #[test] #[ignore] -fn test_function_with_explicit_runtime_dependency_js_heroku_22() { - test_node_function( - "functions/with-explicit-runtime-dependency-js", - Heroku22, +fn test_function_with_explicit_runtime_dependency_js() { + function_integration_test( + "../../../test/fixtures/functions/with-explicit-runtime-dependency-js", |ctx| { assert_contains!( ctx.pack_stdout, "Node.js function runtime declared in package.json" ); assert_not_contains!(ctx.pack_stderr, "Future versions of the Functions Runtime for Node.js (@heroku/sf-fx-runtime-nodejs) will not be auto-detected and must be added as a dependency in package.json"); - assert_health_check_responds(&ctx); + start_container_and_assert_health_check_responds(&ctx); }, ); } #[test] #[ignore] -fn test_function_with_explicit_runtime_dependency_ts_heroku_22() { - test_node_function( - "functions/with-explicit-runtime-dependency-ts", - Heroku22, +fn test_function_with_explicit_runtime_dependency_ts() { + function_integration_test( + "../../../test/fixtures/functions/with-explicit-runtime-dependency-ts", |ctx| { assert_contains!( ctx.pack_stdout, "Node.js function runtime declared in package.json" ); assert_not_contains!(ctx.pack_stderr, "Future versions of the Functions Runtime for Node.js (@heroku/sf-fx-runtime-nodejs) will not be auto-detected and must be added as a dependency in package.json"); - assert_health_check_responds(&ctx); + start_container_and_assert_health_check_responds(&ctx); }, ); } #[test] #[ignore] -fn test_function_with_implicit_runtime_dependency_js_heroku_22() { - test_node_function( - "functions/with-implicit-runtime-dependency-js", - Heroku22, +fn test_function_with_implicit_runtime_dependency_js() { + function_integration_test( + "../../../test/fixtures/functions/with-implicit-runtime-dependency-js", |ctx| { assert_contains!(ctx.pack_stderr, "Future versions of the Functions Runtime for Node.js (@heroku/sf-fx-runtime-nodejs) will not be auto-detected and must be added as a dependency in package.json"); assert_not_contains!( ctx.pack_stdout, "Node.js function runtime declared in package.json" ); - assert_health_check_responds(&ctx); + start_container_and_assert_health_check_responds(&ctx); }, ); } #[test] #[ignore] -fn test_function_with_implicit_runtime_dependency_ts_heroku_22() { - test_node_function( - "functions/with-implicit-runtime-dependency-ts", - Heroku22, +fn test_function_with_implicit_runtime_dependency_ts() { + function_integration_test( + "../../../test/fixtures/functions/with-implicit-runtime-dependency-ts", |ctx| { assert_contains!(ctx.pack_stderr, "Future versions of the Functions Runtime for Node.js (@heroku/sf-fx-runtime-nodejs) will not be auto-detected and must be added as a dependency in package.json"); assert_not_contains!( ctx.pack_stdout, "Node.js function runtime declared in package.json" ); - assert_health_check_responds(&ctx); + start_container_and_assert_health_check_responds(&ctx); }, ); } + +fn invoke_function(socket_addr: &SocketAddr, payload: &serde_json::Value) -> serde_json::Value { + let id = format!("MyFunction-{}", random_hex_string(10)); + + let sf_context = base64_encode_json(&serde_json::json!({ + "apiVersion": "", + "payloadVersion": "", + "userContext": { + "orgId": "", + "userId": "", + "username": "", + "orgDomainUrl": "", + "onBehalfOfUserId": serde_json::Value::Null, + "salesforceBaseUrl": "" + } + })); + + let ssfn_context = base64_encode_json(&serde_json::json!({ + "resource": "", + "requestId": "", + "accessToken": "", + "apexClassId": serde_json::Value::Null, + "apexClassFQN": serde_json::Value::Null, + "functionName": "", + "functionInvocationId": serde_json::Value::Null + })); + + let response = retry(DEFAULT_RETRIES, DEFAULT_RETRY_DELAY, || { + ureq::post(&format!("http://{socket_addr}")) + .set("Content-Type", "application/json") + .set("Authorization", "") + .set("ce-id", &id) + .set("ce-time", "2020-09-03T20:56:28.297915Z") + .set("ce-type", "") + .set("ce-source", "") + .set("ce-specversion", "1.0") + .set("ce-sfcontext", &sf_context) + .set("ce-sffncontext", &ssfn_context) + .send_json(payload.clone()) + }) + .unwrap(); + + response.into_json().expect("expected response to be json") +} + +fn assert_health_check_responds(socket_addr: &SocketAddr) { + let response = retry(DEFAULT_RETRIES, DEFAULT_RETRY_DELAY, || { + ureq::post(&format!("http://{socket_addr}")) + .set("x-health-check", "true") + .call() + }) + .unwrap(); + let response_body = response.into_string().unwrap(); + assert_contains!(response_body, "OK"); +} + +fn start_container_and_assert_health_check_responds(ctx: &TestContext) { + start_container(ctx, |_container, socket_addr| { + assert_health_check_responds(socket_addr); + }); +} + +fn random_hex_string(length: usize) -> String { + let mut bytes = Vec::with_capacity(length); + rand::thread_rng().fill_bytes(&mut bytes); + hex::encode(&bytes) +} + +fn base64_encode_json(value: &serde_json::Value) -> String { + let json_string = serde_json::to_string(value).expect("Value should be encodable as JSON"); + base64::engine::general_purpose::STANDARD.encode(json_string) +} diff --git a/buildpacks/nodejs-npm-engine/inventory.toml b/buildpacks/nodejs-npm-engine/inventory.toml index cf3f3d36..110f2843 100644 --- a/buildpacks/nodejs-npm-engine/inventory.toml +++ b/buildpacks/nodejs-npm-engine/inventory.toml @@ -1,29 +1,125 @@ name = "npm" +[[releases]] +version = "10.0.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v10.0.0.tar.gz" +etag = "76deb9389081c39e579893229d5eae52" + +[[releases]] +version = "10.1.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v10.1.0.tar.gz" +etag = "0349d02bce8d37dc140532bf430759da" + +[[releases]] +version = "10.2.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v10.2.0.tar.gz" +etag = "dda9858dd5e9ce23882acb9835dd1966" + [[releases]] version = "8.0.0" channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.0.0.tar.gz" etag = "f57e5811cb6e26d00b8b06e1eea67c65" +[[releases]] +version = "8.1.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.1.0.tar.gz" +etag = "0a29c338adba902749b7bb265007bab9" + +[[releases]] +version = "8.1.1" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.1.1.tar.gz" +etag = "5996c416396cdd330ddc3a7540a1f18d" + +[[releases]] +version = "8.1.2" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.1.2.tar.gz" +etag = "6c5b07cc8552123ec82e7403fe1e2f0f" + +[[releases]] +version = "8.1.3" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.1.3.tar.gz" +etag = "83e60269c91ed4606161b9803dd9ed30" + +[[releases]] +version = "8.1.4" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.1.4.tar.gz" +etag = "be0df53c851b31d4d507a4bcd8689933" + +[[releases]] +version = "8.10.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.10.0.tar.gz" +etag = "325b552c2ed890aef120fa4d13292114" + +[[releases]] +version = "8.11.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.11.0.tar.gz" +etag = "2c3c661e95ef0503816fb0319c152093" + [[releases]] version = "8.12.0" channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.12.0.tar.gz" etag = "576b8b3f3c082fd4316b8e1ab9e73c74" +[[releases]] +version = "8.12.1" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.12.1.tar.gz" +etag = "71d59274edd60f15c053d0236fdd2bbe" + +[[releases]] +version = "8.12.2" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.12.2.tar.gz" +etag = "afcc70608c87a0583a325e9fe4281e25" + +[[releases]] +version = "8.13.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.13.0.tar.gz" +etag = "2a6a6603fddb70939609bc933bb31f93" + [[releases]] version = "8.13.1" channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.13.1.tar.gz" etag = "5e7e57ef4d8ac7ad6744716ae334bc93" +[[releases]] +version = "8.13.2" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.13.2.tar.gz" +etag = "4eb61d6ee6415c32f5ca360741c7024e" + +[[releases]] +version = "8.14.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.14.0.tar.gz" +etag = "192c90ee0ecd40511685a7d3a568c33c" + [[releases]] version = "8.15.0" channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.15.0.tar.gz" etag = "080f4eff8f327063315a273346edfd6d" +[[releases]] +version = "8.15.1" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.15.1.tar.gz" +etag = "c86616f24edef13b44faec0119ac65fe" + [[releases]] version = "8.16.0" channel = "release" @@ -36,6 +132,42 @@ channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.17.0.tar.gz" etag = "3a4dad8e78d927befbb77ae84a0773bd" +[[releases]] +version = "8.18.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.18.0.tar.gz" +etag = "4cc6097152a77bfdca8593f476c3db6a" + +[[releases]] +version = "8.19.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.19.0.tar.gz" +etag = "f2658620f95443db7d317ee113493365" + +[[releases]] +version = "8.19.1" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.19.1.tar.gz" +etag = "04159b834f76086fecd2337db3a3224d" + +[[releases]] +version = "8.19.2" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.19.2.tar.gz" +etag = "886f933d3d8955ff150d713ae9725ba5" + +[[releases]] +version = "8.19.3" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.19.3.tar.gz" +etag = "940c84adc0b2492c14c0375ff32cea6c" + +[[releases]] +version = "8.19.4" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.19.4.tar.gz" +etag = "00cdcfb88101c64d910169a6d15e6aa2" + [[releases]] version = "8.2.0" channel = "release" @@ -54,12 +186,24 @@ channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.3.1.tar.gz" etag = "927fad24c43cd064ae2e010d7886732d" +[[releases]] +version = "8.3.2" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.3.2.tar.gz" +etag = "878c74309efeabbd907fab935fe05bb3" + [[releases]] version = "8.4.0" channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.4.0.tar.gz" etag = "e805e6dee82d4f70dfbb353e19917796" +[[releases]] +version = "8.4.1" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.4.1.tar.gz" +etag = "1ed8fc6340d71a12d105c4e7eacf68ae" + [[releases]] version = "8.5.0" channel = "release" @@ -72,18 +216,66 @@ channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.5.1.tar.gz" etag = "5b4c9dcd3dfb70b3ae838a72f3336b9e" +[[releases]] +version = "8.5.2" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.5.2.tar.gz" +etag = "eef4c4e44a99510e0d21952a35b2fa12" + +[[releases]] +version = "8.5.3" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.5.3.tar.gz" +etag = "adaee7af0c32997e1b10138b887b64d7" + +[[releases]] +version = "8.5.4" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.5.4.tar.gz" +etag = "1ca70f32efea790d7d765da9fb0f945e" + [[releases]] version = "8.5.5" channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.5.5.tar.gz" etag = "c3ea22c421f419c940daf6915025f7b1" +[[releases]] +version = "8.6.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.6.0.tar.gz" +etag = "50460002e456814fea3869bc23d3a343" + [[releases]] version = "8.7.0" channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.7.0.tar.gz" etag = "fdd55021ab1efa755ded1decedc63149" +[[releases]] +version = "8.8.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.8.0.tar.gz" +etag = "60f5e3abea1cf0466116115e587f7b07" + +[[releases]] +version = "8.9.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v8.9.0.tar.gz" +etag = "5befe879deb83adaa644be39a841251b" + +[[releases]] +version = "9.0.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.0.0.tar.gz" +etag = "2afebf2e6192dc5dad60479e21be5e0a" + +[[releases]] +version = "9.0.1" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.0.1.tar.gz" +etag = "ac1bf9cdea7a8027118e63d3ec719f4e" + [[releases]] version = "9.1.0" channel = "release" @@ -96,18 +288,48 @@ channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.1.1.tar.gz" etag = "18d7655ca1a6ca49e5303edddbe5ad14" +[[releases]] +version = "9.1.2" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.1.2.tar.gz" +etag = "be2bf5582ea3cf887ae11375b54254f6" + [[releases]] version = "9.1.3" channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.1.3.tar.gz" etag = "f6d39cec10e75f8f61bb465f0e1964f2" +[[releases]] +version = "9.2.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.2.0.tar.gz" +etag = "1a1714da4d8169f2229be7c4457d38b1" + +[[releases]] +version = "9.3.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.3.0.tar.gz" +etag = "0073b825084c551fa2d13420ab439e20" + [[releases]] version = "9.3.1" channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.3.1.tar.gz" etag = "9a3e9f5d0c3357e68bf4810ecac0306b" +[[releases]] +version = "9.4.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.4.0.tar.gz" +etag = "40af9283db14b4f01ab6c81677dd7221" + +[[releases]] +version = "9.4.1" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.4.1.tar.gz" +etag = "1f7d00ce4e2ea14f75b9d70677185145" + [[releases]] version = "9.4.2" channel = "release" @@ -120,6 +342,12 @@ channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.5.0.tar.gz" etag = "2dc0b3d652470c78eba35ce6edc82454" +[[releases]] +version = "9.5.1" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.5.1.tar.gz" +etag = "58e994784a937c1afd392b9ada600822" + [[releases]] version = "9.6.0" channel = "release" @@ -132,6 +360,24 @@ channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.6.1.tar.gz" etag = "445470c705ba61da5da3742fe02528bf" +[[releases]] +version = "9.6.2" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.6.2.tar.gz" +etag = "f8c27527296077334574f98c99330d89" + +[[releases]] +version = "9.6.3" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.6.3.tar.gz" +etag = "9ccac52b1e317d0a23759ff7f8200b01" + +[[releases]] +version = "9.6.4" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.6.4.tar.gz" +etag = "7f6a72bf960610de1c905ade67bc0dc7" + [[releases]] version = "9.6.5" channel = "release" @@ -144,3 +390,39 @@ channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.6.6.tar.gz" etag = "aebff29bee406bcc491573f00106edd2" +[[releases]] +version = "9.6.7" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.6.7.tar.gz" +etag = "b85f34d64a8224a25221c5b57b8a29e5" + +[[releases]] +version = "9.7.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.7.0.tar.gz" +etag = "290bb0fc344dd0da80732d7703d3614a" + +[[releases]] +version = "9.7.1" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.7.1.tar.gz" +etag = "aaa52932b8cf3ccad629f9e14ca39ad2" + +[[releases]] +version = "9.7.2" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.7.2.tar.gz" +etag = "10d35fb2b79993038464ce698ec0d2c5" + +[[releases]] +version = "9.8.0" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.8.0.tar.gz" +etag = "f7d03233261854ef783504dfbb103f23" + +[[releases]] +version = "9.8.1" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/npm/release/npm-v9.8.1.tar.gz" +etag = "a54b82af3b9133e8d9a4825ee04bbbb1" + diff --git a/buildpacks/nodejs-pnpm-install/CHANGELOG.md b/buildpacks/nodejs-pnpm-install/CHANGELOG.md index ad2f61a5..535ea2dc 100644 --- a/buildpacks/nodejs-pnpm-install/CHANGELOG.md +++ b/buildpacks/nodejs-pnpm-install/CHANGELOG.md @@ -2,11 +2,19 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [1.1.6] - 2023-09-25 + +- No changes. + +## [1.1.5] - 2023-09-19 + +- No changes. + ## [1.1.4] - 2023-08-10 - No changes. @@ -36,9 +44,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Initial release ([#488](https://github.com/heroku/buildpacks-nodejs/pull/488)) -[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...HEAD +[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.6...HEAD +[1.1.6]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.5...v1.1.6 +[1.1.5]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...v1.1.5 [1.1.4]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.3...v1.1.4 [1.1.3]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.2...v1.1.3 [1.1.2]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.1...v1.1.2 [1.1.1]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.0...v1.1.1 -[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 \ No newline at end of file +[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 diff --git a/buildpacks/nodejs-pnpm-install/README.md b/buildpacks/nodejs-pnpm-install/README.md index 8101af4b..b7df4c1d 100644 --- a/buildpacks/nodejs-pnpm-install/README.md +++ b/buildpacks/nodejs-pnpm-install/README.md @@ -99,11 +99,11 @@ command from Cloud Native Buildpacks using pack build example-app-image --buildpack heroku/nodejs-engine --buildpack heroku/nodejs-corepack --buildpack heroku/nodejs-pnpm-install --path /some/example-app ``` -Alternatively, use the `heroku/buildpacks:22` builder, which includes the above +Alternatively, use the `heroku/builder:22` builder, which includes the above buildpacks: ``` -pack build example-app-image --builder heroku/buildpacks:22 --path /some/example-app +pack build example-app-image --builder heroku/builder:22 --path /some/example-app ``` ## Additional Info diff --git a/buildpacks/nodejs-pnpm-install/buildpack.toml b/buildpacks/nodejs-pnpm-install/buildpack.toml index 1f4a0a9a..41a92af5 100644 --- a/buildpacks/nodejs-pnpm-install/buildpack.toml +++ b/buildpacks/nodejs-pnpm-install/buildpack.toml @@ -2,7 +2,7 @@ api = "0.9" [buildpack] id = "heroku/nodejs-pnpm-install" -version = "1.1.4" +version = "1.1.6" name = "Heroku Node.js pnpm install" homepage = "https://github.com/heroku/buildpacks-nodejs" keywords = ["node", "node.js", "nodejs", "javascript", "js", "pnpm"] diff --git a/buildpacks/nodejs-pnpm-install/tests/integration_test.rs b/buildpacks/nodejs-pnpm-install/tests/integration_test.rs index dc873045..6171e6a7 100644 --- a/buildpacks/nodejs-pnpm-install/tests/integration_test.rs +++ b/buildpacks/nodejs-pnpm-install/tests/integration_test.rs @@ -2,13 +2,12 @@ use indoc::formatdoc; use libcnb_test::{assert_contains, assert_empty}; -use test_support::Builder::{Heroku20, Heroku22}; -use test_support::{assert_web_response, test_pnpm_app}; +use test_support::{assert_web_response, nodejs_integration_test}; #[test] #[ignore = "integration test"] -fn pnpm_7_pnp_heroku_20() { - test_pnpm_app("pnpm-7-pnp", Heroku20, |ctx| { +fn pnpm_7_pnp() { + nodejs_integration_test("../../../test/fixtures/pnpm-7-pnp", |ctx| { assert_empty!(ctx.pack_stderr); assert_contains!( ctx.pack_stdout, @@ -58,8 +57,8 @@ fn pnpm_7_pnp_heroku_20() { #[test] #[ignore = "integration test"] -fn pnpm_8_hoist_heroku_22() { - test_pnpm_app("pnpm-8-hoist", Heroku22, |ctx| { +fn pnpm_8_hoist() { + nodejs_integration_test("../../../test/fixtures/pnpm-8-hoist", |ctx| { assert_empty!(ctx.pack_stderr); assert_contains!( ctx.pack_stdout, diff --git a/buildpacks/nodejs-yarn/CHANGELOG.md b/buildpacks/nodejs-yarn/CHANGELOG.md index 9e91a08a..0920a636 100644 --- a/buildpacks/nodejs-yarn/CHANGELOG.md +++ b/buildpacks/nodejs-yarn/CHANGELOG.md @@ -2,11 +2,26 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +- Added Yarn version 4.0.0-rc.53. +- Added Yarn version 4.0.0-rc.52. +- Added Yarn version 3.6.4. +## [1.1.6] - 2023-09-25 + +- No changes. + +## [1.1.5] - 2023-09-19 + +- Added Yarn version 4.0.0-rc.51. +- Added Yarn version 4.0.0-rc.50. +- Added Yarn version 4.0.0-rc.49. +- Added Yarn version 3.6.3. +- Added Yarn version 3.6.2. + ## [1.1.4] - 2023-08-10 - No changes. @@ -128,9 +143,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Changelog entry for first release ([#1](https://github.com/heroku/nodejs-yarn-buildpack/pull/1)) -[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...HEAD +[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.6...HEAD +[1.1.6]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.5...v1.1.6 +[1.1.5]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...v1.1.5 [1.1.4]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.3...v1.1.4 [1.1.3]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.2...v1.1.3 [1.1.2]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.1...v1.1.2 [1.1.1]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.0...v1.1.1 -[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 \ No newline at end of file +[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 diff --git a/buildpacks/nodejs-yarn/buildpack.toml b/buildpacks/nodejs-yarn/buildpack.toml index 5605c3c4..c49ca85b 100644 --- a/buildpacks/nodejs-yarn/buildpack.toml +++ b/buildpacks/nodejs-yarn/buildpack.toml @@ -2,7 +2,7 @@ api = "0.9" [buildpack] id = "heroku/nodejs-yarn" -version = "1.1.4" +version = "1.1.6" name = "Heroku Node.js Yarn" homepage = "https://github.com/heroku/buildpacks-nodejs" keywords = ["node", "node.js", "nodejs", "javascript", "js", "yarn", "yarnpkg"] diff --git a/buildpacks/nodejs-yarn/inventory.toml b/buildpacks/nodejs-yarn/inventory.toml index df84c980..4df9756f 100644 --- a/buildpacks/nodejs-yarn/inventory.toml +++ b/buildpacks/nodejs-yarn/inventory.toml @@ -828,6 +828,24 @@ channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/yarn/release/yarn-v3.6.1.tar.gz" etag = "69dd9c5317552e7db1a6b5393b3168c2" +[[releases]] +version = "3.6.2" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/yarn/release/yarn-v3.6.2.tar.gz" +etag = "2477fb8fb76f5ef96360fc85620d80f4" + +[[releases]] +version = "3.6.3" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/yarn/release/yarn-v3.6.3.tar.gz" +etag = "cd87545d08991cb3089d89bfb60716f0" + +[[releases]] +version = "3.6.4" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/yarn/release/yarn-v3.6.4.tar.gz" +etag = "c39c39f159d1c5170ef1d38a41e80aaf" + [[releases]] version = "4.0.0-rc.35" channel = "release" @@ -912,3 +930,33 @@ channel = "release" url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/yarn/release/yarn-v4.0.0-rc.48.tar.gz" etag = "c202595e39bec0030ea6b2b091a0b6a3" +[[releases]] +version = "4.0.0-rc.49" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/yarn/release/yarn-v4.0.0-rc.49.tar.gz" +etag = "dbb6782c7c7715406b5db25b32d106a7" + +[[releases]] +version = "4.0.0-rc.50" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/yarn/release/yarn-v4.0.0-rc.50.tar.gz" +etag = "96350f65ac4b0f33b4e8d300ac4c1cec" + +[[releases]] +version = "4.0.0-rc.51" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/yarn/release/yarn-v4.0.0-rc.51.tar.gz" +etag = "b23bee873d416ec64cf88b80de604327" + +[[releases]] +version = "4.0.0-rc.52" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/yarn/release/yarn-v4.0.0-rc.52.tar.gz" +etag = "453dcad2d81a1d26c17ea665ced5543e" + +[[releases]] +version = "4.0.0-rc.53" +channel = "release" +url = "https://heroku-nodebin.s3.us-east-1.amazonaws.com/yarn/release/yarn-v4.0.0-rc.53.tar.gz" +etag = "c0d6abdde92df88fc17e0bf8ef57b9a3" + diff --git a/buildpacks/nodejs-yarn/tests/integration_test.rs b/buildpacks/nodejs-yarn/tests/integration_test.rs index 7cd5f769..afa4cdbf 100644 --- a/buildpacks/nodejs-yarn/tests/integration_test.rs +++ b/buildpacks/nodejs-yarn/tests/integration_test.rs @@ -1,92 +1,58 @@ #![warn(clippy::pedantic)] use libcnb_test::{assert_contains, assert_not_contains}; -use test_support::Builder::{Heroku20, Heroku22}; -use test_support::{assert_web_response, test_yarn_app}; +use test_support::{assert_web_response, nodejs_integration_test}; #[test] #[ignore = "integration test"] -fn yarn_1_typescript_heroku_20() { - test_yarn_app("yarn-1-typescript", Heroku20, |ctx| { - assert_contains!(ctx.pack_stdout, "Installing yarn"); +fn yarn_1_typescript() { + nodejs_integration_test("../../../test/fixtures/yarn-1-typescript", |ctx| { + assert_contains!(ctx.pack_stdout, "Installing Node"); + assert_contains!(ctx.pack_stdout, "Installing yarn CLI"); assert_contains!(ctx.pack_stdout, "Installing dependencies"); assert_contains!(ctx.pack_stdout, "Running `build` script"); - assert_web_response(&ctx, "yarn-1-typescript"); - }); -} -#[test] -#[ignore = "integration test"] -fn yarn_1_typescript_heroku_22() { - test_yarn_app("yarn-1-typescript", Heroku22, |ctx| { - assert_contains!(ctx.pack_stdout, "Installing yarn"); - assert_contains!(ctx.pack_stdout, "Installing dependencies"); - assert_contains!(ctx.pack_stdout, "Running `build` script"); + assert_not_contains!(ctx.pack_stdout, "corepack"); + assert_not_contains!( + ctx.pack_stdout, + "Installing node modules from ./package-lock.json" + ); + assert_web_response(&ctx, "yarn-1-typescript"); }); } #[test] #[ignore = "integration test"] -fn yarn_2_pnp_zero_heroku_20() { - test_yarn_app("yarn-2-pnp-zero", Heroku20, |ctx| { - assert_contains!(ctx.pack_stdout, "Installing yarn"); +fn yarn_2_pnp_zero() { + nodejs_integration_test("../../../test/fixtures/yarn-2-pnp-zero", |ctx| { + assert_contains!(ctx.pack_stdout, "Installing Node"); + assert_contains!(ctx.pack_stdout, "Installing yarn 2.4.1 via corepack"); assert_contains!(ctx.pack_stdout, "Yarn zero-install detected"); assert_contains!(ctx.pack_stdout, "Installing dependencies"); - assert_not_contains!( - ctx.pack_stdout, - "can't be found in the cache and will be fetched from the remote registry" - ); assert_contains!(ctx.pack_stdout, "Resolution step"); assert_contains!(ctx.pack_stdout, "Fetch step"); assert_contains!(ctx.pack_stdout, "Link step"); assert_contains!(ctx.pack_stdout, "Completed"); - assert_web_response(&ctx, "yarn-2-pnp-zero"); - }); -} -#[test] -#[ignore = "integration test"] -fn yarn_2_pnp_zero_heroku_22() { - test_yarn_app("yarn-2-pnp-zero", Heroku22, |ctx| { - assert_contains!(ctx.pack_stdout, "Installing yarn"); - assert_contains!(ctx.pack_stdout, "Yarn zero-install detected"); - assert_contains!(ctx.pack_stdout, "Installing dependencies"); + assert_not_contains!(ctx.pack_stdout, "Installing yarn CLI"); assert_not_contains!( ctx.pack_stdout, - "can't be found in the cache and will be fetched from the remote registry" + "Installing node modules from ./package-lock.json" ); - assert_contains!(ctx.pack_stdout, "Resolution step"); - assert_contains!(ctx.pack_stdout, "Fetch step"); - assert_contains!(ctx.pack_stdout, "Link step"); - assert_contains!(ctx.pack_stdout, "Completed"); - assert_web_response(&ctx, "yarn-2-pnp-zero"); - }); -} - -#[test] -#[ignore = "integration test"] -fn yarn_2_modules_nonzero_heroku_20() { - test_yarn_app("yarn-2-modules-nonzero", Heroku20, |ctx| { - assert_contains!(ctx.pack_stdout, "Installing yarn"); - assert_contains!(ctx.pack_stdout, "Successfully set cacheFolder"); - assert_contains!(ctx.pack_stdout, "Installing dependencies"); - assert_contains!( + assert_not_contains!( ctx.pack_stdout, "can't be found in the cache and will be fetched from the remote registry" ); - assert_contains!(ctx.pack_stdout, "Resolution step"); - assert_contains!(ctx.pack_stdout, "Fetch step"); - assert_contains!(ctx.pack_stdout, "Link step"); - assert_contains!(ctx.pack_stdout, "Completed"); - assert_web_response(&ctx, "yarn-2-modules-nonzero"); + + assert_web_response(&ctx, "yarn-2-pnp-zero"); }); } #[test] #[ignore = "integration test"] -fn yarn_2_modules_nonzero_heroku_22() { - test_yarn_app("yarn-2-modules-nonzero", Heroku22, |ctx| { +fn yarn_2_modules_nonzero() { + nodejs_integration_test("../../../test/fixtures/yarn-2-modules-nonzero", |ctx| { assert_contains!(ctx.pack_stdout, "Installing yarn"); assert_contains!(ctx.pack_stdout, "Successfully set cacheFolder"); assert_contains!(ctx.pack_stdout, "Installing dependencies"); @@ -104,8 +70,8 @@ fn yarn_2_modules_nonzero_heroku_22() { #[test] #[ignore = "integration test"] -fn yarn_3_pnp_nonzero_heroku_20() { - test_yarn_app("yarn-3-pnp-nonzero", Heroku20, |ctx| { +fn yarn_3_pnp_nonzero() { + nodejs_integration_test("../../../test/fixtures/yarn-3-pnp-nonzero", |ctx| { assert_contains!(ctx.pack_stdout, "Installing yarn"); assert_contains!(ctx.pack_stdout, "Installing dependencies"); assert_contains!(ctx.pack_stdout, "Successfully set cacheFolder"); @@ -123,46 +89,8 @@ fn yarn_3_pnp_nonzero_heroku_20() { #[test] #[ignore = "integration test"] -fn yarn_3_pnp_nonzero_heroku_22() { - test_yarn_app("yarn-3-pnp-nonzero", Heroku22, |ctx| { - assert_contains!(ctx.pack_stdout, "Installing yarn"); - assert_contains!(ctx.pack_stdout, "Successfully set cacheFolder"); - assert_contains!(ctx.pack_stdout, "Installing dependencies"); - assert_contains!( - ctx.pack_stdout, - "can't be found in the cache and will be fetched from the remote registry" - ); - assert_contains!(ctx.pack_stdout, "Resolution step"); - assert_contains!(ctx.pack_stdout, "Fetch step"); - assert_contains!(ctx.pack_stdout, "Link step"); - assert_contains!(ctx.pack_stdout, "Completed"); - assert_web_response(&ctx, "yarn-3-pnp-nonzero"); - }); -} - -#[test] -#[ignore = "integration test"] -fn yarn_3_modules_zero_heroku_20() { - test_yarn_app("yarn-3-modules-zero", Heroku20, |ctx| { - assert_contains!(ctx.pack_stdout, "Installing yarn"); - assert_contains!(ctx.pack_stdout, "Yarn zero-install detected"); - assert_contains!(ctx.pack_stdout, "Installing dependencies"); - assert_not_contains!( - ctx.pack_stdout, - "can't be found in the cache and will be fetched from the remote registry" - ); - assert_contains!(ctx.pack_stdout, "Resolution step"); - assert_contains!(ctx.pack_stdout, "Fetch step"); - assert_contains!(ctx.pack_stdout, "Link step"); - assert_contains!(ctx.pack_stdout, "Completed"); - assert_web_response(&ctx, "yarn-3-modules-zero"); - }); -} - -#[test] -#[ignore = "integration test"] -fn yarn_3_modules_zero_heroku_22() { - test_yarn_app("yarn-3-modules-zero", Heroku22, |ctx| { +fn yarn_3_modules_zero() { + nodejs_integration_test("../../../test/fixtures/yarn-3-modules-zero", |ctx| { assert_contains!(ctx.pack_stdout, "Installing yarn"); assert_contains!(ctx.pack_stdout, "Yarn zero-install detected"); assert_contains!(ctx.pack_stdout, "Installing dependencies"); diff --git a/buildpacks/npm/CHANGELOG.md b/buildpacks/npm/CHANGELOG.md index b6ef785e..d8b89ee4 100644 --- a/buildpacks/npm/CHANGELOG.md +++ b/buildpacks/npm/CHANGELOG.md @@ -2,11 +2,19 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [1.1.6] - 2023-09-25 + +- No changes. + +## [1.1.5] - 2023-09-19 + +- No changes. + ## [1.1.4] - 2023-08-10 - No changes. @@ -127,9 +135,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fix broken builds when a `package-lock.json` is missing ([#9](https://github.com/heroku/nodejs-npm-buildpack/pull/9)) -[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...HEAD +[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.6...HEAD +[1.1.6]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.5...v1.1.6 +[1.1.5]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...v1.1.5 [1.1.4]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.3...v1.1.4 [1.1.3]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.2...v1.1.3 [1.1.2]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.1...v1.1.2 [1.1.1]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.0...v1.1.1 -[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 \ No newline at end of file +[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 diff --git a/buildpacks/npm/buildpack.toml b/buildpacks/npm/buildpack.toml index f1fe4ed9..deff6147 100644 --- a/buildpacks/npm/buildpack.toml +++ b/buildpacks/npm/buildpack.toml @@ -2,7 +2,7 @@ api = "0.6" [buildpack] id = "heroku/nodejs-npm" -version = "1.1.4" +version = "1.1.6" name = "NPM Buildpack" homepage = "https://github.com/heroku/buildpacks-nodejs" keywords = ["nodejs", "node", "npm"] diff --git a/common/bin/download-verify-node b/common/bin/download-verify-node index 7f5a99f7..5ec8ea10 100755 --- a/common/bin/download-verify-node +++ b/common/bin/download-verify-node @@ -57,6 +57,7 @@ gpg_keys=( "74F12602B6F1C4E913FAA37AD3A89613643B6201" "141F07595B7B3FFE74309A937405533BE57C7D57" "DD792F5973C6DE52C432CBDAC77ABFA00DDBF2B7" + "A363A499291CBBC940DD62E41F10027AF002F8B0" ) for key in "${gpg_keys[@]}"; do gpg --keyserver hkps://keys.openpgp.org --recv-keys "$key" diff --git a/common/bin/download-verify-npm-package b/common/bin/download-verify-npm-package index 090718fa..9b6574b1 100755 --- a/common/bin/download-verify-npm-package +++ b/common/bin/download-verify-npm-package @@ -7,9 +7,9 @@ set -o pipefail set -e -package_name=$1 -if [ "npm" != "${package_name}" ] && [ "yarn" != "${package_name}" ]; then - echo "Unrecognized distribution - ${package_name}" +distribution_name=$1 +if [ "npm" != "${distribution_name}" ] && [ "yarn" != "${distribution_name}" ]; then + echo "Unrecognized distribution - ${distribution_name}" exit 1 fi @@ -19,6 +19,7 @@ if [ -z "$package_version" ]; then exit 1 fi +package_name="${distribution_name}" if [ "yarn" = "${package_name}" ]; then # Yarn 2+ (aka: "berry") is hosted under a different npm package. major_version=$(echo "$package_version" | cut -d "." -f 1) @@ -26,21 +27,24 @@ if [ "yarn" = "${package_name}" ]; then fi npm_url="https://registry.npmjs.com/${package_name}/${package_version}" - echo "Determining dist url from ${npm_url}" >&2 -url=$(curl -sSf "${npm_url}" | jq -r '.dist.tarball') -echo "Downloading ${package_name} tarball from ${url} ..." >&2 -curl -sSf -o "./${package_name}-v${package_version}.tar.gz" "${url}" +tarball_url=$(curl --silent --show-error --fail --retry 5 --retry-all-errors --connect-timeout 10 --max-time 60 "${npm_url}" | jq -r '.dist.tarball') +echo "Downloading ${package_name} tarball from ${tarball_url} ..." >&2 + +downloaded_tarball="./${distribution_name}-v${package_version}.tar.gz" +echo "Saving as ${downloaded_tarball}" >&2 + +curl --silent --show-error --fail --retry 5 --retry-all-errors --connect-timeout 10 --max-time 60 --output "${downloaded_tarball}" "${tarball_url}" # Check the file's sha against npm's published sha. This section assumes all # packages are published with sha512. That was true at the time of writing, # but if npmjs.org starts using additional checksum algorithms, this section # will need to be changed. echo "Checking ${package_name} tarball integrity..." >&2 -shasum=$(shasum -b -a 512 "${package_name}"-v"${package_version}".tar.gz | awk '{ print $1 }' | xxd -r -p | base64 | tr -d "\n") +shasum=$(shasum -b -a 512 "${downloaded_tarball}" | awk '{ print $1 }' | xxd -r -p | base64 | tr -d "\n") actual_integrity="sha512-${shasum}" -published_integrity=$(curl -sSf "https://registry.npmjs.com/${package_name}/${package_version}" | jq -r '.dist.integrity') +published_integrity=$(curl --silent --show-error --fail --retry 5 --retry-all-errors --connect-timeout 10 --max-time 60 "${npm_url}" | jq -r '.dist.integrity') if [ "$actual_integrity" != "$published_integrity" ]; then echo "Couldn't verify package integrity. Expected '$published_integrity', got '$actual_integrity'." >&2 exit 1 @@ -56,7 +60,7 @@ npm_pubkey="MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp printf -- '-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n' "$npm_pubkey" >npm-pubkey.pem # Fetch the signature from the published package data -curl -sSf "https://registry.npmjs.com/${package_name}/${package_version}" | jq -r '.dist.signatures[0].sig' | base64 -d >npm-signature.bin +curl --silent --show-error --fail --retry 5 --retry-all-errors --connect-timeout 10 --max-time 60 "${npm_url}" | jq -r '.dist.signatures[0].sig' | base64 -d >npm-signature.bin # Build the signing message echo -n "${package_name}@${package_version}:${published_integrity}" >message.txt diff --git a/common/nodejs-utils/Cargo.toml b/common/nodejs-utils/Cargo.toml index 1709908f..1d959c12 100644 --- a/common/nodejs-utils/Cargo.toml +++ b/common/nodejs-utils/Cargo.toml @@ -18,6 +18,9 @@ thiserror.workspace = true toml.workspace = true ureq = { workspace = true, features = ["json"] } url = "2" +opentelemetry.workspace = true +opentelemetry-stdout = { version = "0.1.0", features = ["trace"] } +opentelemetry_sdk = { version = "0.20.0", features = ["trace"] } [dev-dependencies] tempfile.workspace = true diff --git a/common/nodejs-utils/src/lib.rs b/common/nodejs-utils/src/lib.rs index b543fc84..73f1b0fb 100644 --- a/common/nodejs-utils/src/lib.rs +++ b/common/nodejs-utils/src/lib.rs @@ -9,4 +9,5 @@ mod nodejs_org; mod npmjs_org; pub mod package_json; mod s3; +pub mod telemetry; pub mod vrs; diff --git a/common/nodejs-utils/src/telemetry.rs b/common/nodejs-utils/src/telemetry.rs new file mode 100644 index 00000000..e8bb0bf5 --- /dev/null +++ b/common/nodejs-utils/src/telemetry.rs @@ -0,0 +1,82 @@ +use std::{ + fs::{create_dir_all, File}, + path::Path, +}; + +use opentelemetry::{ + global::{self, BoxedTracer}, + KeyValue, +}; +use opentelemetry_sdk::{ + trace::{Config, TracerProvider}, + Resource, +}; + +pub fn init_tracer(buildpack_name: impl Into) -> BoxedTracer { + let bp_name = buildpack_name.into(); + let telem_file_path = Path::new("/tmp") + .join("cnb-telemetry") + .join(format!("{}.jsonl", bp_name.replace('/', "_"))); + if let Some(parent_dir) = telem_file_path.parent() { + let _ = create_dir_all(parent_dir); + } + let exporter = match File::create(telem_file_path) { + Ok(f) => opentelemetry_stdout::SpanExporter::builder() + .with_writer(f) + .build(), + Err(_) => opentelemetry_stdout::SpanExporter::default(), + }; + let provider = TracerProvider::builder() + .with_config( + Config::default().with_resource(Resource::new(vec![KeyValue::new( + "service.name", + bp_name.clone(), + )])), + ) + .with_simple_exporter(exporter) + .build(); + global::set_tracer_provider(provider); + global::tracer(bp_name) +} + +#[cfg(test)] +mod tests { + use std::fs::{self}; + + use super::init_tracer; + use opentelemetry::{global, trace::TraceContextExt, trace::Tracer}; + + #[test] + fn test_tracer_writes_span_file() -> Result<(), String> { + let buildpack_name = "heroku_test_buildpack"; + let test_span_name = "test_span_1"; + let test_event_name = "test_event_1"; + let telemetry_file_path = format!("/tmp/cnb-telemetry/{buildpack_name}.jsonl"); + + let _ = fs::remove_file(&telemetry_file_path); + + init_tracer(buildpack_name.to_string()); + let tracer = global::tracer(""); + tracer.in_span(test_span_name, |cx| { + cx.span().add_event(test_event_name, Vec::new()); + }); + global::shutdown_tracer_provider(); + let contents = fs::read_to_string(telemetry_file_path) + .expect("expected to read existing telemetry file"); + println!("{contents}"); + + if !contents.contains(buildpack_name) { + Err("File export did not include buildpack name")?; + } + + if !contents.contains(test_span_name) { + Err("File export did not include test span")?; + } + + if !contents.contains(test_event_name) { + Err("File export did not include test event")?; + } + + Ok(()) + } +} diff --git a/meta-buildpacks/nodejs-function/CHANGELOG.md b/meta-buildpacks/nodejs-function/CHANGELOG.md index ca88cb65..67b1542f 100644 --- a/meta-buildpacks/nodejs-function/CHANGELOG.md +++ b/meta-buildpacks/nodejs-function/CHANGELOG.md @@ -2,11 +2,23 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [1.1.6] - 2023-09-25 + +- Updated `heroku/nodejs-engine` to `1.1.6`. +- Updated `heroku/nodejs-function-invoker` to `1.1.6`. +- Updated `heroku/nodejs-npm` to `1.1.6`. + +## [1.1.5] - 2023-09-19 + +- Updated `heroku/nodejs-engine` to `1.1.5`. +- Updated `heroku/nodejs-function-invoker` to `1.1.5`. +- Updated `heroku/nodejs-npm` to `1.1.5`. + ## [1.1.4] - 2023-08-10 - Updated `heroku/nodejs-engine` to `1.1.4`. @@ -269,9 +281,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed * Switch from the Riff based invoker buildpacks to `heroku/nodejs-function` ([#48](https://github.com/heroku/buildpacks-node/pull/48)) -[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...HEAD +[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.6...HEAD +[1.1.6]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.5...v1.1.6 +[1.1.5]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...v1.1.5 [1.1.4]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.3...v1.1.4 [1.1.3]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.2...v1.1.3 [1.1.2]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.1...v1.1.2 [1.1.1]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.0...v1.1.1 -[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 \ No newline at end of file +[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 diff --git a/meta-buildpacks/nodejs-function/build.sh b/meta-buildpacks/nodejs-function/build.sh deleted file mode 100755 index edc11a77..00000000 --- a/meta-buildpacks/nodejs-function/build.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# This script is present to support cutlass integration tests which looks for a `build.sh` file and, if found, will -# execute it to produce a compiled buildpack which it then expects to find in the ./target directory. - -buildpack_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" -cd "$buildpack_dir" -output_dir=$(cargo libcnb package --release) -mv "$output_dir" "${buildpack_dir}/target" diff --git a/meta-buildpacks/nodejs-function/buildpack.toml b/meta-buildpacks/nodejs-function/buildpack.toml index 285ba3b2..f8bbd41c 100644 --- a/meta-buildpacks/nodejs-function/buildpack.toml +++ b/meta-buildpacks/nodejs-function/buildpack.toml @@ -2,7 +2,7 @@ api = "0.9" [buildpack] id = "heroku/nodejs-function" -version = "1.1.4" +version = "1.1.6" name = "Node.js Function" homepage = "https://github.com/heroku/buildpacks-nodejs" @@ -13,15 +13,15 @@ type = "MIT" [[order.group]] id = "heroku/nodejs-engine" -version = "1.1.4" +version = "1.1.6" [[order.group]] id = "heroku/nodejs-npm" -version = "1.1.4" +version = "1.1.6" [[order.group]] id = "heroku/nodejs-function-invoker" -version = "1.1.4" +version = "1.1.6" [metadata] [metadata.release] diff --git a/meta-buildpacks/nodejs/CHANGELOG.md b/meta-buildpacks/nodejs/CHANGELOG.md index ead389d8..e02c27d2 100644 --- a/meta-buildpacks/nodejs/CHANGELOG.md +++ b/meta-buildpacks/nodejs/CHANGELOG.md @@ -2,12 +2,27 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [1.1.6] - 2023-09-25 + +- Updated `heroku/nodejs-corepack` to `1.1.6`. +- Updated `heroku/nodejs-engine` to `1.1.6`. +- Updated `heroku/nodejs-npm` to `1.1.6`. +- Updated `heroku/nodejs-pnpm-install` to `1.1.6`. +- Updated `heroku/nodejs-yarn` to `1.1.6`. + +## [1.1.5] - 2023-09-19 + - Updated `heroku/procfile` to `2.0.1`. ([#639](https://github.com/heroku/buildpacks-node/pull/639)) +- Updated `heroku/nodejs-corepack` to `1.1.5`. +- Updated `heroku/nodejs-engine` to `1.1.5`. +- Updated `heroku/nodejs-npm` to `1.1.5`. +- Updated `heroku/nodejs-pnpm-install` to `1.1.5`. +- Updated `heroku/nodejs-yarn` to `1.1.5`. ## [1.1.4] - 2023-08-10 @@ -240,9 +255,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed * Package meta buildpack with latest releases of buildpacks while testing against unreleased. -[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...HEAD +[unreleased]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.6...HEAD +[1.1.6]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.5...v1.1.6 +[1.1.5]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.4...v1.1.5 [1.1.4]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.3...v1.1.4 [1.1.3]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.2...v1.1.3 [1.1.2]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.1...v1.1.2 [1.1.1]: https://github.com/heroku/buildpacks-nodejs/compare/v1.1.0...v1.1.1 -[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 \ No newline at end of file +[1.1.0]: https://github.com/heroku/buildpacks-nodejs/releases/tag/v1.1.0 diff --git a/meta-buildpacks/nodejs/build.sh b/meta-buildpacks/nodejs/build.sh deleted file mode 100755 index edc11a77..00000000 --- a/meta-buildpacks/nodejs/build.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# This script is present to support cutlass integration tests which looks for a `build.sh` file and, if found, will -# execute it to produce a compiled buildpack which it then expects to find in the ./target directory. - -buildpack_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" -cd "$buildpack_dir" -output_dir=$(cargo libcnb package --release) -mv "$output_dir" "${buildpack_dir}/target" diff --git a/meta-buildpacks/nodejs/buildpack.toml b/meta-buildpacks/nodejs/buildpack.toml index 931dd382..cdd408c4 100644 --- a/meta-buildpacks/nodejs/buildpack.toml +++ b/meta-buildpacks/nodejs/buildpack.toml @@ -2,7 +2,7 @@ api = "0.9" [buildpack] id = "heroku/nodejs" -version = "1.1.4" +version = "1.1.6" name = "Node.js" homepage = "https://github.com/heroku/buildpacks-nodejs" @@ -13,15 +13,15 @@ type = "MIT" [[order.group]] id = "heroku/nodejs-engine" -version = "1.1.4" +version = "1.1.6" [[order.group]] id = "heroku/nodejs-corepack" -version = "1.1.4" +version = "1.1.6" [[order.group]] id = "heroku/nodejs-pnpm-install" -version = "1.1.4" +version = "1.1.6" [[order.group]] id = "heroku/procfile" @@ -32,16 +32,16 @@ optional = true [[order.group]] id = "heroku/nodejs-engine" -version = "1.1.4" +version = "1.1.6" [[order.group]] id = "heroku/nodejs-corepack" -version = "1.1.4" +version = "1.1.6" optional = true [[order.group]] id = "heroku/nodejs-yarn" -version = "1.1.4" +version = "1.1.6" [[order.group]] id = "heroku/procfile" @@ -52,16 +52,16 @@ optional = true [[order.group]] id = "heroku/nodejs-engine" -version = "1.1.4" +version = "1.1.6" [[order.group]] id = "heroku/nodejs-npm-engine" -version = "1.1.4" +version = "1.1.6" optional = true [[order.group]] id = "heroku/nodejs-npm" -version = "1.1.4" +version = "1.1.6" [[order.group]] id = "heroku/procfile" diff --git a/test/specs/node-function/cutlass/function_spec.rb b/test/specs/node-function/cutlass/function_spec.rb deleted file mode 100644 index e3d5728e..00000000 --- a/test/specs/node-function/cutlass/function_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -require_relative "../spec_helper" - -describe "Heroku's Nodejs CNB" do - let(:builder) { "heroku/builder:22" } - - it "generates a callable salesforce function" do - Cutlass::App.new("simple-function", builder: builder).transaction do |app| - app.pack_build do |pack_result| - expect(pack_result.stdout).to include("Installing Node.js Function Invoker") - end - - app.start_container(expose_ports: 8080, memory: 1e9) do |container| - body = { } - query = Cutlass::FunctionQuery.new( - port: container.get_host_port(8080), - body: body - ).call - - expect(query.as_json).to eq("hello world") - expect(query.success?).to be_truthy - - expect(container.logs.stdout).to include("logging info is a fun 1") - end - end - end - - it "generates a callable salesforce function from typescript" do - Cutlass::App.new("simple-typescript-function", builder: builder).transaction do |app| - app.pack_build do |pack_result| - expect(pack_result.stdout).to include("Installing Node.js Function Invoker") - end - - app.start_container(expose_ports: 8080, memory: 1e9) do |container| - body = { } - query = Cutlass::FunctionQuery.new( - port: container.get_host_port(8080), - body: body - ).call - - expect(query.as_json).to eq("hello world from typescript") - expect(query.success?).to be_truthy - end - end - end -end diff --git a/test/specs/node-function/spec_helper.rb b/test/specs/node-function/spec_helper.rb deleted file mode 100644 index 251ae1b5..00000000 --- a/test/specs/node-function/spec_helper.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -require "rspec/core" -require "rspec/retry" - -require "cutlass" - -def test_dir - Pathname(__dir__).join("../..") -end - -NODEJS_FUNCTION_BUILDPACK = Cutlass::LocalBuildpack.new(directory: test_dir.join("../meta-buildpacks/nodejs-function")) -Cutlass.config do |config| - config.default_buildpack_paths = [NODEJS_FUNCTION_BUILDPACK] - config.default_builder = "heroku/buildpacks:20" - config.default_repo_dirs = [test_dir.join("fixtures")] -end - -RSpec.configure do |config| - # config.filter_run :focus => true - - config.before(:suite) do - Cutlass::CleanTestEnv.record - end - - config.after(:suite) do - NODEJS_FUNCTION_BUILDPACK.teardown - Cutlass::CleanTestEnv.check - end -end - diff --git a/test/specs/node/cutlass/basic_spec.rb b/test/specs/node/cutlass/basic_spec.rb deleted file mode 100644 index 771a8a2a..00000000 --- a/test/specs/node/cutlass/basic_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -# frozen_string_literal: true - -require_relative "../spec_helper" - - -describe "Heroku's Nodejs CNB" do - ["heroku/buildpacks:20", "heroku/builder:22"].each do |builder| - describe "with #{builder}" do - it "handles a downgrade of node engine" do - Cutlass::App.new("simple-function", builder: builder).transaction do |app| - set_node_version_in_dir(app.tmpdir, version: "^14.0") - - app.pack_build do |pack_result| - expect(pack_result.stdout).to include("Installing Node.js 14.") - end - - set_node_version_in_dir(app.tmpdir, version: "^16.0") - - app.pack_build do |pack_result| - expect(pack_result.stdout).to include("Installing Node.js 16.") - end - end - end - - it "installs dependencies using NPM if no lock file exists" do - Cutlass::App.new("npm-project", builder: builder).transaction do |app| - app.pack_build do |pack_result| - expect(pack_result.stdout).to include("Installing Node") - expect(pack_result.stdout).to_not include("Installing yarn") - expect(pack_result.stdout).to include("Installing node modules") - expect(pack_result.stdout).to_not include("Installing node modules from ./yarn.lock") - expect(pack_result.stdout).to_not include("Installing node modules from ./package-lock.json") - end - end - end - - it "installs dependencies using NPM if package-lock.json exists" do - Cutlass::App.new("npm-project-with-lockfile", builder: builder).transaction do |app| - app.pack_build do |pack_result| - expect(pack_result.stdout).to include("Installing Node") - expect(pack_result.stdout).to_not include("Installing yarn") - expect(pack_result.stdout).to include("Installing node modules") - expect(pack_result.stdout).to_not include("Installing node modules from ./yarn.lock") - expect(pack_result.stdout).to include("Installing node modules from ./package-lock.json") - end - end - end - - it "Installs yarn and installs dependencies with yarn if yarn.lock exists" do - Cutlass::App.new("yarn-1-typescript", builder: builder).transaction do |app| - app.pack_build do |pack_result| - expect(pack_result.stdout).to include("Installing Node") - expect(pack_result.stdout).to_not include("corepack") - expect(pack_result.stdout).to include("Installing yarn CLI") - expect(pack_result.stdout).to include("Installing dependencies"); - expect(pack_result.stdout).to_not include("Installing node modules from ./package-lock.json") - expect(pack_result.stdout).to include("Running `build` script"); - end - end - end - - it "Installs yarn with corepack and installs dependencies if yarn.lock exists and packageManager is yarn" do - Cutlass::App.new("yarn-2-pnp-zero", builder: builder).transaction do |app| - app.pack_build do |pack_result| - expect(pack_result.stdout).to include("Installing Node") - expect(pack_result.stdout).to include("Installing yarn 2.4.1 via corepack") - expect(pack_result.stdout).to_not include("Installing yarn CLI") - expect(pack_result.stdout).to include("Installing dependencies"); - expect(pack_result.stdout).to_not include("Installing node modules from ./package-lock.json") - end - end - end - end - end -end diff --git a/test/specs/node/spec_helper.rb b/test/specs/node/spec_helper.rb deleted file mode 100644 index 5b0dc2f0..00000000 --- a/test/specs/node/spec_helper.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -require "rspec/core" -require "rspec/retry" - -require "cutlass" - -def test_dir - Pathname(__dir__).join("../..") -end - -NODEJS_BUILDPACK = Cutlass::LocalBuildpack.new(directory: test_dir.join("../meta-buildpacks/nodejs")) - -Cutlass.config do |config| - config.default_buildpack_paths = [NODEJS_BUILDPACK] - config.default_builder = "heroku/buildpacks:20" - config.default_repo_dirs = [test_dir.join("fixtures")] -end - -RSpec.configure do |config| - # config.filter_run :focus => true - - config.before(:suite) do - Cutlass::CleanTestEnv.record - end - - config.after(:suite) do - NODEJS_BUILDPACK.teardown - Cutlass::CleanTestEnv.check - end -end - -def set_node_version_in_dir(dir, version: ) - package_json = Pathname(dir).join("package.json") - package_json_hash = JSON.parse(package_json.read) - package_json_hash["engines"]["node"] = version - package_json.write(package_json_hash.to_json) -end diff --git a/test_support/Cargo.toml b/test_support/Cargo.toml index ff43c47a..86869aba 100644 --- a/test_support/Cargo.toml +++ b/test_support/Cargo.toml @@ -7,7 +7,8 @@ edition.workspace = true publish.workspace = true [dependencies] -libcnb-data.workspace = true +libcnb.workspace = true libcnb-test.workspace = true +serde_json.workspace = true tempfile.workspace = true ureq.workspace = true diff --git a/test_support/src/lib.rs b/test_support/src/lib.rs index c0018e0c..555c1e91 100644 --- a/test_support/src/lib.rs +++ b/test_support/src/lib.rs @@ -1,167 +1,159 @@ -use libcnb_data::buildpack_id; +use libcnb::data::buildpack_id; use libcnb_test::{ - assert_contains, BuildConfig, BuildpackReference, ContainerConfig, TestContext, TestRunner, + assert_contains, BuildConfig, BuildpackReference, ContainerConfig, ContainerContext, + TestContext, TestRunner, }; -use std::fmt::Formatter; -use std::path::PathBuf; +use std::net::SocketAddr; +use std::path::{Path, PathBuf}; use std::time::Duration; -use std::{env, fmt}; - -const PORT: u16 = 8080; -const TIMEOUT: u64 = 10; const DEFAULT_BUILDER: &str = "heroku/builder:22"; +pub const PORT: u16 = 8080; +pub const DEFAULT_RETRIES: u32 = 10; +pub const DEFAULT_RETRY_DELAY: Duration = Duration::from_secs(1); pub fn get_integration_test_builder() -> String { - env::var("INTEGRATION_TEST_CNB_BUILDER").unwrap_or(DEFAULT_BUILDER.to_string()) + std::env::var("INTEGRATION_TEST_CNB_BUILDER").unwrap_or(DEFAULT_BUILDER.to_string()) } pub fn nodejs_integration_test(fixture: &str, test_body: fn(TestContext)) { - let cargo_manifest_dir = env::var("CARGO_MANIFEST_DIR") + nodejs_integration_test_with_config(fixture, |_| {}, test_body); +} + +pub fn nodejs_integration_test_with_config( + fixture: &str, + with_config: fn(&mut BuildConfig), + test_body: fn(TestContext), +) { + integration_test_with_config( + fixture, + with_config, + test_body, + &[BuildpackReference::WorkspaceBuildpack(buildpack_id!( + "heroku/nodejs" + ))], + ); +} + +pub fn function_integration_test(fixture: &str, test_body: fn(TestContext)) { + function_integration_test_with_config(fixture, |_| {}, test_body); +} + +pub fn function_integration_test_with_config( + fixture: &str, + with_config: fn(&mut BuildConfig), + test_body: fn(TestContext), +) { + if get_integration_test_builder() == "heroku/builder:20" { + // builder:20 doesn't ship with functions + return; + } + integration_test_with_config( + fixture, + with_config, + test_body, + &[BuildpackReference::WorkspaceBuildpack(buildpack_id!( + "heroku/nodejs-function" + ))], + ); +} + +fn integration_test_with_config( + fixture: &str, + with_config: fn(&mut BuildConfig), + test_body: fn(TestContext), + buildpacks: &[BuildpackReference], +) { + let cargo_manifest_dir = std::env::var("CARGO_MANIFEST_DIR") .map(PathBuf::from) .expect("The CARGO_MANIFEST_DIR should be automatically set by Cargo when running tests but it was not"); let builder = get_integration_test_builder(); let app_dir = cargo_manifest_dir.join("tests").join(fixture); - let buildpacks = vec![BuildpackReference::LibCnbRs(buildpack_id!("heroku/nodejs"))]; let mut build_config = BuildConfig::new(builder, app_dir); build_config.buildpacks(buildpacks); + with_config(&mut build_config); TestRunner::default().build(build_config, test_body); } -pub enum Builder { - Heroku20, - Heroku22, -} - -impl fmt::Display for Builder { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match *self { - Builder::Heroku20 => write!(f, "heroku/buildpacks:20"), - Builder::Heroku22 => write!(f, "heroku/builder:22"), +pub fn retry( + attempts: u32, + retry_delay: Duration, + retryable_action: impl Fn() -> Result, +) -> Result { + let mut result = retryable_action(); + for _ in 1..attempts { + if result.is_ok() { + return result; } + std::thread::sleep(retry_delay); + result = retryable_action(); } + result } -pub fn get_function_invoker_buildpacks() -> Vec { - vec![ - BuildpackReference::Other(String::from("heroku/nodejs-engine")), - BuildpackReference::Other(String::from("heroku/nodejs-npm")), - BuildpackReference::Crate, - ] -} - -pub fn get_yarn_buildpacks() -> Vec { - vec![ - BuildpackReference::Other(String::from("heroku/nodejs-engine")), - BuildpackReference::Crate, - ] -} - -pub fn get_corepack_buildpacks() -> Vec { - vec![ - BuildpackReference::Other(String::from("heroku/nodejs-engine")), - BuildpackReference::Crate, - ] -} - -pub fn get_pnpm_buildpacks() -> Vec { - vec![ - BuildpackReference::Other(String::from("heroku/nodejs-engine")), - BuildpackReference::Other(String::from("heroku/nodejs-corepack")), - BuildpackReference::Crate, - ] -} - -pub fn get_function_invoker_build_config(fixture: &str, builder: Builder) -> BuildConfig { - BuildConfig::new( - builder.to_string(), - format!("../../test/fixtures/{fixture}"), - ) - .buildpacks(get_function_invoker_buildpacks()) - .to_owned() -} - -pub fn get_yarn_build_config(fixture: &str, builder: Builder) -> BuildConfig { - BuildConfig::new( - builder.to_string(), - format!("../../test/fixtures/{fixture}"), - ) - .buildpacks(get_yarn_buildpacks()) - .to_owned() -} - -pub fn get_corepack_build_config(fixture: &str, builder: Builder) -> BuildConfig { - BuildConfig::new( - builder.to_string(), - format!("../../test/fixtures/{fixture}"), - ) - .buildpacks(get_corepack_buildpacks()) - .to_owned() -} - -pub fn get_pnpm_build_config(fixture: &str, builder: Builder) -> BuildConfig { - BuildConfig::new( - builder.to_string(), - format!("../../test/fixtures/{fixture}"), - ) - .buildpacks(get_pnpm_buildpacks()) - .to_owned() -} - -pub fn test_node_function(fixture: &str, builder: Builder, test_body: fn(TestContext)) { - TestRunner::default().build(get_function_invoker_build_config(fixture, builder), |ctx| { - test_body(ctx) +pub fn start_container(ctx: &TestContext, in_container: impl Fn(&ContainerContext, &SocketAddr)) { + ctx.start_container(ContainerConfig::new().expose_port(PORT), |container| { + let socket_addr = retry(DEFAULT_RETRIES, DEFAULT_RETRY_DELAY, || { + std::panic::catch_unwind(|| container.address_for_port(PORT)) + }) + .unwrap(); + in_container(&container, &socket_addr); }); } -pub fn test_yarn_app(fixture: &str, builder: Builder, test_body: fn(TestContext)) { - TestRunner::default().build(get_yarn_build_config(fixture, builder), |ctx| { - test_body(ctx) +pub fn assert_web_response(ctx: &TestContext, expected_response_body: &'static str) { + start_container(ctx, |_container, socket_addr| { + let response = retry(DEFAULT_RETRIES, DEFAULT_RETRY_DELAY, || { + ureq::get(&format!("http://{socket_addr}/")).call() + }) + .unwrap(); + let response_body = response.into_string().unwrap(); + assert_contains!(response_body, expected_response_body); }); } -pub fn test_corepack_app(fixture: &str, builder: Builder, test_body: fn(TestContext)) { - TestRunner::default().build(get_corepack_build_config(fixture, builder), |ctx| { - test_body(ctx) +pub fn set_node_engine(app_dir: &Path, version_range: &str) { + update_package_json(app_dir, |package_json| { + package_json + .entry("engines") + .or_insert(serde_json::Value::Object(serde_json::Map::new())) + .as_object_mut() + .unwrap() + .insert( + "node".to_string(), + serde_json::Value::String(version_range.to_string()), + ); }); } -pub fn test_pnpm_app(fixture: &str, builder: Builder, test_body: fn(TestContext)) { - TestRunner::default().build(get_pnpm_build_config(fixture, builder), |ctx| { - test_body(ctx) +pub fn set_package_manager(app_dir: &Path, package_manager: &str) { + update_package_json(app_dir, |package_json| { + package_json.insert( + "packageManager".to_string(), + serde_json::Value::String(package_manager.to_string()), + ); }); } -pub fn assert_health_check_responds(ctx: &TestContext) { - ctx.start_container(ContainerConfig::new().expose_port(PORT), |container| { - std::thread::sleep(Duration::from_secs(TIMEOUT)); - - let addr = container.address_for_port(PORT); - let resp = ureq::post(&format!("http://{addr}")) - .set("x-health-check", "true") - .call() - .expect("request to container failed") - .into_string() - .expect("response read error"); - - assert_contains!(resp, "OK") - }) +pub fn update_package_json( + app_dir: &Path, + update: impl FnOnce(&mut serde_json::Map), +) { + update_json_file(&app_dir.join("package.json"), |json| { + update( + json.as_object_mut() + .expect("Deserialized package.json value should be an object"), + ) + }); } -pub fn assert_web_response(ctx: &TestContext, text: &'static str) { - ctx.start_container(ContainerConfig::new().expose_port(PORT), |container| { - std::thread::sleep(Duration::from_secs(5)); - - let addr = container.address_for_port(PORT); - let resp = ureq::get(&format!("http://{addr}/")) - .call() - .expect("request to container failed") - .into_string() - .expect("response read error"); - - assert_contains!(resp, text); - }) +pub fn update_json_file(path: &Path, update: impl FnOnce(&mut serde_json::Value)) { + let json_file = std::fs::read_to_string(path).unwrap(); + let mut json: serde_json::Value = serde_json::from_str(&json_file).unwrap(); + update(&mut json); + let new_contents = serde_json::to_string(&json).unwrap(); + std::fs::write(path, new_contents).unwrap(); }