ronantakizawa/codereview-bench huggingface dataset:
Repository: helix-editor/helix
File: helix-lsp/src/lib.rs (Rust)

Code before:
use helix_core::syntax::config::{
    LanguageConfiguration, LanguageServerConfiguration, LanguageServerFeatures,
};
use helix_stdx::path;
use slotmap::SlotMap;
use tokio::sync::mpsc::UnboundedReceiver;

use std::{
    collections::HashMap,
    path::{Path, PathBuf},
    sync::Arc,
};

use thiserror::Error;
use tokio_stream::wrappers::UnboundedReceiverStream;

pub type Result<T, E = Error> = core::result::Result<T, E>;
pub type LanguageServerName = String;
pub use helix_core::diagnostic::LanguageServerId;

#[derive(Error, Debug)]
pub enum Error {
    #[error("protocol error: {0}")]
    Rpc(#[from] jsonrpc::Error),
    #[error("failed to parse: {0}")]
    Parse(Box<dyn std::error::Error + Send + Sync>),
    #[error("IO Error: {0}")]
    IO(#[from] std::io::Error),
    #[error("request {0} timed out")]
    Timeout(jsonrpc::Id),
    #[error("server closed the stream")]
    StreamClosed,
    #[error("Unhandled")]
    Unhandled,
    #[error(transparent)]
    ExecutableNotFound(#[from] helix_stdx::env::ExecutableNotFoundError),
    #[error(transparent)]
    Other(#[from] anyhow::Error),
}

impl From<serde_json::Error> for Error {
    fn from(value: serde_json::Error) -> Self {
        Self::Parse(Box::new(value))
    }
}

impl From<simd_json::Error> for Error {
    fn from(value: simd_json::Error) -> Self {
        Self::Parse(Box::new(value))
    }
}

Review comment (suggestion):
I guess I could also make an enum for this and have `ParseError { SerdeJson(serde_json::Error), SimdJson(simd_json::Error) }`? Then have `Parse(ParseError)`.

Code after:
use helix_core::syntax::config::{
    LanguageConfiguration, LanguageServerConfiguration, LanguageServerFeatures,
};
use helix_stdx::path;
use slotmap::SlotMap;
use tokio::sync::mpsc::UnboundedReceiver;

use std::{
    collections::HashMap,
    path::{Path, PathBuf},
    sync::Arc,
};

use thiserror::Error;
use tokio_stream::wrappers::UnboundedReceiverStream;

pub type Result<T, E = Error> = core::result::Result<T, E>;
pub type LanguageServerName = String;
pub use helix_core::diagnostic::LanguageServerId;

#[derive(Error, Debug)]
pub enum Error {
    #[error("protocol error: {0}")]
    Rpc(#[from] jsonrpc::Error),
    #[error("failed to parse: {0}")]
    Parse(Box<dyn std::error::Error + Send + Sync>),
    #[error("IO Error: {0}")]
    IO(#[from] std::io::Error),
    #[error("request {0} timed out")]
    Timeout(jsonrpc::Id),
    #[error("server closed the stream")]
    StreamClosed,
    #[error("Unhandled")]
    Unhandled,
    #[error(transparent)]
    ExecutableNotFound(#[from] helix_stdx::env::ExecutableNotFoundError),
    #[error(transparent)]
    Other(#[from] anyhow::Error),
}

impl From<serde_json::Error> for Error {
    fn from(value: serde_json::Error) -> Self {
        Self::Parse(Box::new(value))
    }
}

impl From<sonic_rs::Error> for Error {
    fn from(value: sonic_rs::Error) -> Self {
        Self::Parse(Box::new(value))
    }
}
Repository: helix-editor/helix
File: helix-term/src/commands/typed.rs (Rust)

Code before:
            cx.editor
                .language_servers
                .file_event_handler
                .file_changed(path.clone());
        }

        for view_id in view_ids {
            let view = view_mut!(cx.editor, view_id);
            if view.doc.eq(&doc_id) {
                view.ensure_cursor_in_view(doc, scrolloff);
            }
        }
    }

    Ok(())
}

/// Update the [`Document`] if it has been modified.
fn update(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> anyhow::Result<()> {
    if event != PromptEvent::Validate {
        return Ok(());
    }

    let (_view, doc) = current!(cx.editor);
    if doc.is_modified() {
        write(cx, args, event)
    } else {
        Ok(())
    }
}

fn lsp_workspace_command(
    cx: &mut compositor::Context,
    args: Args,
    event: PromptEvent,
) -> anyhow::Result<()> {
    if event != PromptEvent::Validate {
        return Ok(());
    }

    let doc = doc!(cx.editor);
    let ls_id_commands = doc
        .language_servers_with_feature(LanguageServerFeature::WorkspaceCommand)
        .flat_map(|ls| {
            ls.capabilities()
                .execute_command_provider
                .iter()
                .flat_map(|options| options.commands.iter())
                .map(|command| (ls.id(), command))
        });


Review comment (suggestion):
I think we could get away with not updating this line (i.e. only add the `flags` configuration) but OTOH it does seem slightly undesirable to call another typable command function directly rather than its _impl, and this is more explicit that a path can't possibly be passed. So, 👍

Code after:
            cx.editor
                .language_servers
                .file_event_handler
                .file_changed(path.clone());
        }

        for view_id in view_ids {
            let view = view_mut!(cx.editor, view_id);
            if view.doc.eq(&doc_id) {
                view.ensure_cursor_in_view(doc, scrolloff);
            }
        }
    }

    Ok(())
}

/// Update the [`Document`] if it has been modified.
fn update(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> anyhow::Result<()> {
    if event != PromptEvent::Validate {
        return Ok(());
    }

    let (_view, doc) = current!(cx.editor);
    if doc.is_modified() {
        write_impl(
            cx,
            None,
            WriteOptions {
                force: false,
                auto_format: !args.has_flag(WRITE_NO_FORMAT_FLAG.name),
            },
        )
    } else {
        Ok(())
    }
}

fn lsp_workspace_command(
    cx: &mut compositor::Context,
    args: Args,
    event: PromptEvent,
) -> anyhow::Result<()> {
    if event != PromptEvent::Validate {
        return Ok(());
    }

    let doc = doc!(cx.editor);
    let ls_id_commands = doc
        .language_servers_with_feature(LanguageServerFeature::WorkspaceCommand)
        .flat_map(|ls| {
Repository: helix-editor/helix
File: helix-term/src/commands/typed.rs (Rust)

Code before:
        format!("Invalid register {}", &args[0])
    );
    let register = args[0].chars().next().unwrap_or_default();
    if cx.editor.registers.remove(register) {
        cx.editor
            .set_status(format!("Register {} cleared", register));
    } else {
        cx.editor
            .set_error(format!("Register {} not found", register));
    }
    Ok(())
}

fn set_register(
    cx: &mut compositor::Context,
    args: Args,
    event: PromptEvent,
) -> anyhow::Result<()> {
    if event != PromptEvent::Validate {
        return Ok(());
    }

    ensure!(
        args.len() == 2,
        format!("Expected exactly 2 arguments, got {}", args.len())
    );

    ensure!(
        args[0].chars().count() == 1,
        format!("Invalid register {}", &args[0])
    );

    let register = args[0].chars().next().unwrap_or_default();
    cx.editor.registers.write(register, vec![args[1].into()])
}

fn redraw(cx: &mut compositor::Context, _args: Args, event: PromptEvent) -> anyhow::Result<()> {
    if event != PromptEvent::Validate {
        return Ok(());
    }

    let callback = Box::pin(async move {
        let call: job::Callback =
            job::Callback::EditorCompositor(Box::new(|_editor, compositor| {
                compositor.need_full_redraw();
            }));

        Ok(call)
    });

    cx.jobs.callback(callback);

Review comment (suggestion):
This part can be removed: the `positionals` field in the `Signature` of the command ensures that this function is only called when there are exactly 2 args

Code after:
        format!("Invalid register {}", &args[0])
    );
    let register = args[0].chars().next().unwrap_or_default();
    if cx.editor.registers.remove(register) {
        cx.editor
            .set_status(format!("Register {} cleared", register));
    } else {
        cx.editor
            .set_error(format!("Register {} not found", register));
    }
    Ok(())
}

fn set_register(
    cx: &mut compositor::Context,
    args: Args,
    event: PromptEvent,
) -> anyhow::Result<()> {
    if event != PromptEvent::Validate {
        return Ok(());
    }

    ensure!(
        args[0].chars().count() == 1,
        format!("Invalid register {}", &args[0])
    );

    let register = args[0].chars().next().unwrap_or_default();
    cx.editor.registers.write(register, vec![args[1].into()])
}

fn redraw(cx: &mut compositor::Context, _args: Args, event: PromptEvent) -> anyhow::Result<()> {
    if event != PromptEvent::Validate {
        return Ok(());
    }

    let callback = Box::pin(async move {
        let call: job::Callback =
            job::Callback::EditorCompositor(Box::new(|_editor, compositor| {
                compositor.need_full_redraw();
            }));

        Ok(call)
    });

    cx.jobs.callback(callback);

    Ok(())
}

fn move_buffer(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> anyhow::Result<()> {
Repository: helix-editor/helix
File: helix-stdx/src/faccess.rs (Rust)

Code before:
use bitflags::bitflags;

// Licensed under MIT from faccess
bitflags! {
    /// Access mode flags for `access` function to test for.
    pub struct AccessMode: u8 {
        /// Path exists
        const EXISTS  = 0b0001;
        /// Path can likely be read
        const READ    = 0b0010;
        /// Path can likely be written to
        const WRITE   = 0b0100;
        /// Path can likely be executed
        const EXECUTE = 0b1000;
    }
}

#[cfg(unix)]
mod imp {
    use super::*;

    use rustix::fs::Access;
    use std::os::unix::fs::{MetadataExt, PermissionsExt};

    pub fn access(p: &Path, mode: AccessMode) -> io::Result<()> {
        let mut imode = Access::empty();

        if mode.contains(AccessMode::EXISTS) {
            imode |= Access::EXISTS;
        }

        if mode.contains(AccessMode::READ) {
            imode |= Access::READ_OK;
        }

        if mode.contains(AccessMode::WRITE) {
            imode |= Access::WRITE_OK;
        }

        if mode.contains(AccessMode::EXECUTE) {
            imode |= Access::EXEC_OK;
        }

        rustix::fs::access(p, imode)?;
        Ok(())
    }

    fn chown(p: &Path, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
        let uid = uid.map(rustix::fs::Uid::from_raw);
        let gid = gid.map(rustix::fs::Gid::from_raw);
        rustix::fs::chown(p, uid, gid)?;

Review comment (suggestion):
gated behind `linux` as `CAP_DAC_OVERRIDE` does not exist on other unix-like kernels. See also https://docs.rs/rustix/1.1/rustix/thread/struct.CapabilitySet.html

Code after:
use bitflags::bitflags;

// Licensed under MIT from faccess
bitflags! {
    /// Access mode flags for `access` function to test for.
    pub struct AccessMode: u8 {
        /// Path exists
        const EXISTS  = 0b0001;
        /// Path can likely be read
        const READ    = 0b0010;
        /// Path can likely be written to
        const WRITE   = 0b0100;
        /// Path can likely be executed
        const EXECUTE = 0b1000;
    }
}

#[cfg(unix)]
mod imp {
    use super::*;

    use rustix::fs::Access;
    use std::os::unix::fs::{MetadataExt, PermissionsExt};

    pub fn access(p: &Path, mode: AccessMode) -> io::Result<()> {
        #[cfg(target_os = "linux")]
        {
            // If helix has ambient CAP_DAC_OVERRIDE, everything is accessible regardless of mode bits
            use rustix::thread::{capability_is_in_ambient_set, CapabilitySet};
            if capability_is_in_ambient_set(CapabilitySet::DAC_OVERRIDE).unwrap_or(false) {
                return Ok(());
            }
        }

        let mut imode = Access::empty();

        if mode.contains(AccessMode::EXISTS) {
            imode |= Access::EXISTS;
        }

        if mode.contains(AccessMode::READ) {
            imode |= Access::READ_OK;
        }

        if mode.contains(AccessMode::WRITE) {
            imode |= Access::WRITE_OK;
        }

        if mode.contains(AccessMode::EXECUTE) {
            imode |= Access::EXEC_OK;
        }
Repository: helm/helm
File: pkg/action/action.go (Go)

Code before:
			}
		}
		if d == nil {
			d = driver.NewMemory()
		}
		d.SetNamespace(namespace)
		store = storage.Init(d)
	case "sql":
		d, err := driver.NewSQL(
			os.Getenv("HELM_DRIVER_SQL_CONNECTION_STRING"),
			log,
			namespace,
		)
		if err != nil {
			return errors.Wrap(err, "unable to instantiate SQL driver")
		}
		store = storage.Init(d)
	default:
		return errors.Errorf("unknown driver %q", helmDriver)
	}

	cfg.RESTClientGetter = getter
	cfg.KubeClient = kc
	cfg.Releases = store
	cfg.Log = log
	cfg.HookOutputFunc = defaultHookOutputWriter

	return nil
}

// defaultHookOutputWriter will write the Hook logs to log.Writer().
func defaultHookOutputWriter(_, _, _ string) io.Writer {
	return log.Writer()
}


Review comment (suggestion):
> Additionally, there will be a new item added to the action SDK configuration to allow SDK consumers to get the output. By default this output will be discarded by writing to io.Discard, but an SDK consumer can overwrite the HookOutputFunc to provide a custom writer.

Snippet from the HIP.

We need to allow SDK users to provide their own `HookOutputFunc`. The default would be one that writes to `io.Discard`

Code after:
		}
		if d == nil {
			d = driver.NewMemory()
		}
		d.SetNamespace(namespace)
		store = storage.Init(d)
	case "sql":
		d, err := driver.NewSQL(
			os.Getenv("HELM_DRIVER_SQL_CONNECTION_STRING"),
			log,
			namespace,
		)
		if err != nil {
			return errors.Wrap(err, "unable to instantiate SQL driver")
		}
		store = storage.Init(d)
	default:
		return errors.Errorf("unknown driver %q", helmDriver)
	}

	cfg.RESTClientGetter = getter
	cfg.KubeClient = kc
	cfg.Releases = store
	cfg.Log = log
	cfg.HookOutputFunc = func(_, _, _ string) io.Writer { return io.Discard }

	return nil
}

// SetHookOutputFunc sets the HookOutputFunc on the Configuration.
func (cfg *Configuration) SetHookOutputFunc(hookOutputFunc func(_, _, _ string) io.Writer) {
	cfg.HookOutputFunc = hookOutputFunc
}
Repository: helm/helm
File: pkg/action/show.go (Go)

Code before:
		fmt.Fprintf(&out, "%s\n", cf)
	}

	if (s.OutputFormat == ShowValues || s.OutputFormat == ShowAll) && s.chart.Values != nil {
		if s.OutputFormat == ShowAll {
			fmt.Fprintln(&out, "---")
		}
		if s.JSONPathTemplate != "" {
			printer, err := printers.NewJSONPathPrinter(s.JSONPathTemplate)
			if err != nil {
				return "", errors.Wrapf(err, "error parsing jsonpath %s", s.JSONPathTemplate)
			}
			printer.Execute(&out, s.chart.Values)
		} else {
			for _, f := range s.chart.Raw {
				if f.Name == chartutil.ValuesfileName {
					fmt.Fprintln(&out, string(f.Data))
				}
			}
		}
	}

	if s.OutputFormat == ShowReadme || s.OutputFormat == ShowAll {
		readme := findReadme(s.chart.Files)
		if readme != nil {
			if s.OutputFormat == ShowAll {
				fmt.Fprintln(&out, "---")
			}
			fmt.Fprintf(&out, "%s\n", readme.Data)
		}
	}

	if s.OutputFormat == ShowCRDs || s.OutputFormat == ShowAll {
		crds := s.chart.CRDObjects()
		if len(crds) > 0 {
			for _, crd := range crds {
				if !bytes.HasPrefix(crd.File.Data, []byte("---")) {
					fmt.Fprintln(&out, "---")
				}
				fmt.Fprintf(&out, "%s\n", string(crd.File.Data))
			}
		}
	}
	return out.String(), nil
}

func findReadme(files []*chart.File) (file *chart.File) {
	for _, file := range files {
		for _, n := range readmeFileNames {
			if file == nil {
				continue

Review comment (refactor):
Agree it is appropriate to remove this `s.OutputFormat == ShowAll` logic, as the intention is to always prefix the CRD yaml with `---`

Code after:
				return "", fmt.Errorf("error parsing jsonpath %s: %w", s.JSONPathTemplate, err)
			}
			printer.Execute(&out, s.chart.Values)
		} else {
			for _, f := range s.chart.Raw {
				if f.Name == chartutil.ValuesfileName {
					fmt.Fprintln(&out, string(f.Data))
				}
			}
		}
	}

	if s.OutputFormat == ShowReadme || s.OutputFormat == ShowAll {
		readme := findReadme(s.chart.Files)
		if readme != nil {
			if s.OutputFormat == ShowAll {
				fmt.Fprintln(&out, "---")
			}
			fmt.Fprintf(&out, "%s\n", readme.Data)
		}
	}

	if s.OutputFormat == ShowCRDs || s.OutputFormat == ShowAll {
		crds := s.chart.CRDObjects()
		if len(crds) > 0 {
			for _, crd := range crds {
				if !bytes.HasPrefix(crd.File.Data, []byte("---")) {
					fmt.Fprintln(&out, "---")
				}
				fmt.Fprintf(&out, "%s\n", string(crd.File.Data))
			}
		}
	}
	return out.String(), nil
}

func findReadme(files []*chart.File) (file *chart.File) {
	for _, file := range files {
		for _, n := range readmeFileNames {
			if file == nil {
				continue
			}
			if strings.EqualFold(file.Name, n) {
				return file
			}
		}
	}
	return nil
}
Repository: helm/helm
File: pkg/action/get_metadata.go (Go)

Code before:
		return nil, err
	}

	rel, err := g.cfg.releaseContent(name, g.Version)
	if err != nil {
		return nil, err
	}

	return &Metadata{
		Name:         rel.Name,
		Chart:        rel.Chart.Metadata.Name,
		Version:      rel.Chart.Metadata.Version,
		AppVersion:   rel.Chart.Metadata.AppVersion,
		Dependencies: rel.Chart.Metadata.Dependencies,
		Annotations:  rel.Chart.Metadata.Annotations,
		Namespace:    rel.Namespace,
		Revision:     rel.Version,
		Status:       rel.Info.Status.String(),
		DeployedAt:   rel.Info.LastDeployed.Format(time.RFC3339),
	}, nil
}

// FormattedDepNames formats metadata.dependencies names into a comma-separated list.
func (m *Metadata) FormattedDepNames() string {
	if len(m.Dependencies) == 0 {
		return "<none>"
	}

	depsNames := make([]string, 0, len(m.Dependencies))
	for _, dep := range m.Dependencies {
		depsNames = append(depsNames, dep.Name)
	}
	sort.StringSlice(depsNames).Sort()

	return strings.Join(depsNames, ",")
}


Review comment (suggestion):
To align with other fields that do not produce a result (a good example is App Version), recommend following the same pattern and omitting any output

Code after:
		return nil, err
	}

	rel, err := g.cfg.releaseContent(name, g.Version)
	if err != nil {
		return nil, err
	}

	return &Metadata{
		Name:         rel.Name,
		Chart:        rel.Chart.Metadata.Name,
		Version:      rel.Chart.Metadata.Version,
		AppVersion:   rel.Chart.Metadata.AppVersion,
		Dependencies: rel.Chart.Metadata.Dependencies,
		Annotations:  rel.Chart.Metadata.Annotations,
		Namespace:    rel.Namespace,
		Revision:     rel.Version,
		Status:       rel.Info.Status.String(),
		DeployedAt:   rel.Info.LastDeployed.Format(time.RFC3339),
	}, nil
}

// FormattedDepNames formats metadata.dependencies names into a comma-separated list.
func (m *Metadata) FormattedDepNames() string {
	depsNames := make([]string, 0, len(m.Dependencies))
	for _, dep := range m.Dependencies {
		depsNames = append(depsNames, dep.Name)
	}
	sort.StringSlice(depsNames).Sort()

	return strings.Join(depsNames, ",")
}
Repository: helm/helm
File: pkg/kube/roundtripper.go (Go)

Code before:
		return resp, rtErr
	}
	b, err := io.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return resp, rtErr
	}

	var ke kubernetesError
	r := bytes.NewReader(b)
	err = json.NewDecoder(r).Decode(&ke)
	r.Seek(0, io.SeekStart)
	resp.Body = io.NopCloser(r)
	if err != nil {
		return resp, rtErr
	}
	if ke.Code < 500 {
		return resp, rtErr
	}
	// Matches messages like "etcdserver: leader changed"
	if strings.HasSuffix(ke.Message, "etcdserver: leader changed") {
		return rt.roundTrip(req, retry-1, resp)
	}
	// Matches messages like "rpc error: code = Unknown desc = raft proposal dropped"
	if strings.HasSuffix(ke.Message, "raft proposal dropped") {
		return rt.roundTrip(req, retry-1, resp)
	}
	return resp, nil
}

type kubernetesError struct {
	Message string `json:"message"`
	Code    int    `json:"code"`
}


Review comment (suggestion):
Looks like possible errors on line 61 and 52 above. The whole `rtErr` thing isn't great.

Code after:
		return resp, rtErr
	}
	b, err := io.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return resp, err
	}

	var ke kubernetesError
	r := bytes.NewReader(b)
	err = json.NewDecoder(r).Decode(&ke)
	r.Seek(0, io.SeekStart)
	resp.Body = io.NopCloser(r)
	if err != nil {
		return resp, nil
	}
	if ke.Code < 500 {
		return resp, nil
	}
	// Matches messages like "etcdserver: leader changed"
	if strings.HasSuffix(ke.Message, "etcdserver: leader changed") {
		return rt.roundTrip(req, retry-1, resp)
	}
	// Matches messages like "rpc error: code = Unknown desc = raft proposal dropped"
	if strings.HasSuffix(ke.Message, "raft proposal dropped") {
		return rt.roundTrip(req, retry-1, resp)
	}
	return resp, nil
}

type kubernetesError struct {
	Message string `json:"message"`
	Code    int    `json:"code"`
}
Repository: helm/helm
File: pkg/repo/chartrepo_test.go (Go)

Code before:

import (
	"bytes"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
	"sigs.k8s.io/yaml"

	"helm.sh/helm/v4/pkg/chart"
	"helm.sh/helm/v4/pkg/cli"
	"helm.sh/helm/v4/pkg/getter"
)

const (
	testRepository = "testdata/repository"
	testURL        = "http://example-charts.com"
)

// loadFromDir a directory of charts archives (including sub-directories),
// appending to the repositores ChartPath
func loadFromDir(t *testing.T, r *ChartRepository, dir string) {
	dirInfo, err := os.Stat(dir)
	require.Nil(t, err)
	require.True(t, dirInfo.IsDir())

	globArchives := func(pattern string) []string {
		archives, err := filepath.Glob(filepath.Join(dir, pattern))
		require.Nil(t, err)

		return archives
	}

	r.ChartPaths = append(r.ChartPaths, globArchives("*.tgz")...)
	r.ChartPaths = append(r.ChartPaths, globArchives("**/*.tgz")...)
}

func TestIndex(t *testing.T) {
	r, err := NewChartRepository(&Entry{
		Name: testRepository,
		URL:  testURL,
	}, getter.All(&cli.EnvSettings{}))
	if err != nil {
		t.Errorf("Problem creating chart repository from %s: %v", testRepository, err)
	}

Review comment (suggestion):
This test I removed, as its purpose appears to be to test the `chart.Load()` function

Code after:

import (
	"bytes"
	"net/http"
	"net/http/httptest"
	"os"
	"runtime"
	"strings"
	"testing"
	"time"

	"sigs.k8s.io/yaml"

	"helm.sh/helm/v4/pkg/cli"
	"helm.sh/helm/v4/pkg/getter"
)

type CustomGetter struct {
	repoUrls []string
}

func (g *CustomGetter) Get(href string, _ ...getter.Option) (*bytes.Buffer, error) {
	index := &IndexFile{
		APIVersion: "v1",
		Generated:  time.Now(),
	}
	indexBytes, err := yaml.Marshal(index)
	if err != nil {
		return nil, err
	}
	g.repoUrls = append(g.repoUrls, href)
	return bytes.NewBuffer(indexBytes), nil
}

func TestIndexCustomSchemeDownload(t *testing.T) {
	repoName := "gcs-repo"
	repoURL := "gs://some-gcs-bucket"
	myCustomGetter := &CustomGetter{}
	customGetterConstructor := func(_ ...getter.Option) (getter.Getter, error) {
		return myCustomGetter, nil
	}
	providers := getter.Providers{{
		Schemes: []string{"gs"},
		New:     customGetterConstructor,
	}}
	repo, err := NewChartRepository(&Entry{
		Name: repoName,
		URL:  repoURL,
	}, providers)
	if err != nil {
		t.Fatalf("Problem loading chart repository from %s: %v", repoURL, err)