Skip to content

Commit

Permalink
Replace commons logger with bullet_stream (#993)
Browse files Browse the repository at this point in the history
* Replace `commons` logger with `bullet_stream`

Some of the buildpacks here were early adopters of the output module originally developed [in the Ruby buildpack](https://github.com/heroku/buildpacks-ruby/blob/221fe5bd5bfc5e2715e3810ce353a1252564f012/commons/src/output/mod.rs). This output module has been replaced by [bullet_stream](https://github.com/heroku-buildpacks/bullet_stream).

Eventually, all the buildpacks here will use [bullet_stream](https://github.com/heroku-buildpacks/bullet_stream). For now, I'm just migrating over the existing usage so that I no longer have to deal with errors like this:
 https://github.com/heroku/heroku-buildpack-nodejs/actions/runs/12626267505/job/35179157027#step:4:24
  • Loading branch information
colincasey authored Jan 7, 2025
1 parent 80c97b7 commit c8571b8
Show file tree
Hide file tree
Showing 16 changed files with 349 additions and 544 deletions.
252 changes: 40 additions & 212 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions buildpacks/nodejs-npm-engine/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- Added npm version 11.0.0.
- Replaced `commons` output module with `bullet_stream`. ([#993](https://github.com/heroku/buildpacks-nodejs/pull/993))

## [3.4.0] - 2024-12-13

- No changes.
Expand Down
2 changes: 1 addition & 1 deletion buildpacks/nodejs-npm-engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ edition.workspace = true
workspace = true

[dependencies]
commons = { git = "https://github.com/heroku/buildpacks-ruby", branch = "main" }
bullet_stream = "0.3"
fun_run = "0.2"
heroku-nodejs-utils.workspace = true
indoc = "2"
Expand Down
124 changes: 51 additions & 73 deletions buildpacks/nodejs-npm-engine/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use crate::install_npm::NpmEngineLayerError;
use crate::BUILDPACK_NAME;
use crate::{node, npm};
use commons::output::build_log::{BuildLog, Logger, StartedLogger};
use commons::output::fmt;
use commons::output::fmt::DEBUG_INFO;
use bullet_stream::state::Bullet;
use bullet_stream::{style, Print};
use heroku_nodejs_utils::package_json::PackageJsonError;
use heroku_nodejs_utils::vrs::Requirement;
use indoc::formatdoc;
use std::fmt::Display;
use std::io::stdout;
use std::io::{stdout, Stdout};

const USE_DEBUG_INFORMATION_AND_RETRY_BUILD: &str = "\
Use the debug information above to troubleshoot and retry your build.";
Expand All @@ -29,7 +28,7 @@ pub(crate) enum NpmEngineBuildpackError {
}

pub(crate) fn on_error(error: libcnb::Error<NpmEngineBuildpackError>) {
let logger = BuildLog::new(stdout()).without_buildpack_name();
let logger = Print::new(stdout()).without_header();
match error {
libcnb::Error::BuildpackError(buildpack_error) => {
on_buildpack_error(buildpack_error, logger);
Expand All @@ -38,7 +37,7 @@ pub(crate) fn on_error(error: libcnb::Error<NpmEngineBuildpackError>) {
}
}

fn on_buildpack_error(error: NpmEngineBuildpackError, logger: Box<dyn StartedLogger>) {
fn on_buildpack_error(error: NpmEngineBuildpackError, logger: Print<Bullet<Stdout>>) {
match error {
NpmEngineBuildpackError::PackageJson(e) => on_package_json_error(e, logger),
NpmEngineBuildpackError::MissingNpmEngineRequirement => {
Expand All @@ -54,25 +53,23 @@ fn on_buildpack_error(error: NpmEngineBuildpackError, logger: Box<dyn StartedLog
}
}

fn on_package_json_error(error: PackageJsonError, logger: Box<dyn StartedLogger>) {
fn on_package_json_error(error: PackageJsonError, logger: Print<Bullet<Stdout>>) {
match error {
PackageJsonError::AccessError(e) => {
print_error_details(logger, &e)
.announce()
.error(&formatdoc! {"
.error(formatdoc! {"
Error reading {package_json}.
This buildpack requires {package_json} to complete the build but the file can’t be read.
{USE_DEBUG_INFORMATION_AND_RETRY_BUILD}
{SUBMIT_AN_ISSUE}
", package_json = fmt::value("package.json")});
", package_json = style::value("package.json")});
}
PackageJsonError::ParseError(e) => {
print_error_details(logger, &e)
.announce()
.error(&formatdoc! {"
.error(formatdoc! {"
Error reading {package_json}.
This buildpack requires {package_json} to complete the build but the file \
Expand All @@ -81,39 +78,37 @@ fn on_package_json_error(error: PackageJsonError, logger: Box<dyn StartedLogger>
{USE_DEBUG_INFORMATION_AND_RETRY_BUILD}
{SUBMIT_AN_ISSUE}
", package_json = fmt::value("package.json"), npm_install = fmt::value("npm install") });
", package_json = style::value("package.json"), npm_install = style::value("npm install") });
}
}
}

fn on_missing_npm_engine_requirement_error(logger: Box<dyn StartedLogger>) {
logger.announce().error(&formatdoc! {"
fn on_missing_npm_engine_requirement_error(logger: Print<Bullet<Stdout>>) {
logger.error(formatdoc! {"
Missing {engines_key} key in {package_json}.
This buildpack requires the `engines.npm` key to determine which engine versions to install.
Retry your build.
{SUBMIT_AN_ISSUE}
", engines_key = fmt::value("engines.npm"), package_json = fmt::value("package.json") });
", engines_key = style::value("engines.npm"), package_json = style::value("package.json") });
}

fn on_inventory_parse_error(error: &toml::de::Error, logger: Box<dyn StartedLogger>) {
print_error_details(logger, &error)
.announce()
.error(&formatdoc! {"
fn on_inventory_parse_error(error: &toml::de::Error, logger: Print<Bullet<Stdout>>) {
print_error_details(logger, &error).error(formatdoc! {"
Failed to load available {npm} versions.
An unexpected error occurred while loading the available {npm} versions.
{USE_DEBUG_INFORMATION_AND_RETRY_BUILD}
{SUBMIT_AN_ISSUE}
", npm = fmt::value("npm") });
", npm = style::value("npm") });
}

fn on_npm_version_resolve_error(requirement: &Requirement, logger: Box<dyn StartedLogger>) {
logger.announce().error(&formatdoc! {"
fn on_npm_version_resolve_error(requirement: &Requirement, logger: Print<Bullet<Stdout>>) {
logger.error(formatdoc! {"
Error resolving requested {npm} version {requested_version}.
Can’t find the `npm` version that matches the requested version declared in {package_json} ({requested_version}).
Expand All @@ -128,140 +123,123 @@ fn on_npm_version_resolve_error(requirement: &Requirement, logger: Box<dyn Start
{SUBMIT_AN_ISSUE}
",
npm = fmt::value("npm"),
requested_version = fmt::value(requirement.to_string()),
package_json = fmt::value("package.json"),
engines_key = fmt::value("engines.npm")
npm = style::value("npm"),
requested_version = style::value(requirement.to_string()),
package_json = style::value("package.json"),
engines_key = style::value("engines.npm")
});
}

fn on_npm_engine_layer_error(error: NpmEngineLayerError, logger: Box<dyn StartedLogger>) {
fn on_npm_engine_layer_error(error: NpmEngineLayerError, logger: Print<Bullet<Stdout>>) {
match error {
NpmEngineLayerError::Download(e) => {
print_error_details(logger, &e)
.announce()
.error(&formatdoc! {"
.error(formatdoc! {"
Failed to download {npm}.
An unexpected error occurred while downloading the {npm} package. This error can occur due to an unstable network connection.
{USE_DEBUG_INFORMATION_AND_RETRY_BUILD}
{SUBMIT_AN_ISSUE}
", npm = fmt::value("npm") });
", npm = style::value("npm") });
}
NpmEngineLayerError::OpenTarball(e) => {
print_error_details(logger, &e)
.announce()
.error(&formatdoc! {"
print_error_details(logger, &e).error(formatdoc! {"
An unexpected error occurred while opening the downloaded {npm} package file.
{USE_DEBUG_INFORMATION_AND_RETRY_BUILD}
{SUBMIT_AN_ISSUE}
", npm = fmt::value("npm") });
", npm = style::value("npm") });
}
NpmEngineLayerError::DecompressTarball(e) => {
print_error_details(logger, &e)
.announce()
.error(&formatdoc! {"
.error(formatdoc! {"
An unexpected error occurred while extracting the contents of the downloaded {npm} package file.
{USE_DEBUG_INFORMATION_AND_RETRY_BUILD}
{SUBMIT_AN_ISSUE}
", npm = fmt::value("npm") });
", npm = style::value("npm") });
}
NpmEngineLayerError::RemoveExistingNpmInstall(e) => {
print_error_details(logger, &e)
.announce()
.error(&formatdoc! {"
print_error_details(logger, &e).error(formatdoc! {"
An unexpected error occurred while removing the existing {npm} installation.
{USE_DEBUG_INFORMATION_AND_RETRY_BUILD}
{SUBMIT_AN_ISSUE}
", npm = fmt::value("npm") });
", npm = style::value("npm") });
}
NpmEngineLayerError::InstallNpm(e) => {
print_error_details(logger, &e)
.announce()
.error(&formatdoc! {"
print_error_details(logger, &e).error(formatdoc! {"
An unexpected error occurred while installing the downloaded {npm} package.
{USE_DEBUG_INFORMATION_AND_RETRY_BUILD}
{SUBMIT_AN_ISSUE}
", npm = fmt::value("npm") });
", npm = style::value("npm") });
}
}
}

fn on_node_version_error(error: node::VersionError, logger: Box<dyn StartedLogger>) {
fn on_node_version_error(error: node::VersionError, logger: Print<Bullet<Stdout>>) {
match error {
node::VersionError::Command(e) => {
print_error_details(logger, &e)
.announce()
.error(&formatdoc! {"
print_error_details(logger, &e).error(formatdoc! {"
Failed to determine {node} version information.
An unexpected error occurred while executing {node_version}.
{USE_DEBUG_INFORMATION_AND_RETRY_BUILD}
{SUBMIT_AN_ISSUE}
", node = fmt::value("Node"), node_version = fmt::value(e.name()) });
", node = style::value("Node"), node_version = style::value(e.name()) });
}
node::VersionError::Parse(stdout, e) => {
print_error_details(logger, &e)
.announce()
.error(&formatdoc! {"
print_error_details(logger, &e).error(formatdoc! {"
Failed to parse {node} version information.
An unexpected error occurred while parsing version information from {output}.
{SUBMIT_AN_ISSUE}
", node = fmt::value("Node"), output = fmt::value(stdout) });
", node = style::value("Node"), output = style::value(stdout) });
}
}
}

fn on_npm_version_error(error: npm::VersionError, logger: Box<dyn StartedLogger>) {
fn on_npm_version_error(error: npm::VersionError, logger: Print<Bullet<Stdout>>) {
match error {
npm::VersionError::Command(e) => {
print_error_details(logger, &e)
.announce()
.error(&formatdoc! {"
print_error_details(logger, &e).error(formatdoc! {"
Failed to determine {npm} version information.
An unexpected error occurred while executing {npm_version}.
{USE_DEBUG_INFORMATION_AND_RETRY_BUILD}
{SUBMIT_AN_ISSUE}
", npm = fmt::value("npm"), npm_version = fmt::value(e.name())});
", npm = style::value("npm"), npm_version = style::value(e.name())});
}
npm::VersionError::Parse(stdout, e) => {
print_error_details(logger, &e)
.announce()
.error(&formatdoc! {"
print_error_details(logger, &e).error(formatdoc! {"
Failed to parse {npm} version information.
An unexpected error occurred while parsing version information from {output}.
{SUBMIT_AN_ISSUE}
", npm = fmt::value("npm"), output = fmt::value(stdout) });
", npm = style::value("npm"), output = style::value(stdout) });
}
}
}

fn on_framework_error(
error: &libcnb::Error<NpmEngineBuildpackError>,
logger: Box<dyn StartedLogger>,
logger: Print<Bullet<Stdout>>,
) {
print_error_details(logger, &error)
.announce()
.error(&formatdoc! {"
.error(formatdoc! {"
{buildpack_name} internal error.
The framework used by this buildpack encountered an unexpected error.
Expand All @@ -273,15 +251,15 @@ fn on_framework_error(
the issue locally with a minimal example. Open an issue in the buildpack's GitHub repository \
and include the details.
", buildpack_name = fmt::value(BUILDPACK_NAME) });
", buildpack_name = style::value(BUILDPACK_NAME) });
}

fn print_error_details(
logger: Box<dyn StartedLogger>,
logger: Print<Bullet<Stdout>>,
error: &impl Display,
) -> Box<dyn StartedLogger> {
) -> Print<Bullet<Stdout>> {
logger
.section(DEBUG_INFO)
.step(&error.to_string())
.end_section()
.bullet(style::important("DEBUG INFO:"))
.sub_bullet(error.to_string())
.done()
}
Loading

0 comments on commit c8571b8

Please sign in to comment.