Repository: helm/helm
File: pkg/kube/statuswait.go (Go)

Code before:
	slog.Debug("waiting for resources", "count", len(resourceList), "timeout", timeout)
	sw := watcher.NewDefaultStatusWatcher(w.client, w.restMapper)
	return w.wait(ctx, resourceList, sw)
}

func (w *statusWaiter) WaitWithJobs(resourceList ResourceList, timeout time.Duration) error {
	ctx, cancel := context.WithTimeout(context.TODO(), timeout)
	defer cancel()
	slog.Debug("waiting for resources", "count", len(resourceList), "timeout", timeout)
	sw := watcher.NewDefaultStatusWatcher(w.client, w.restMapper)
	newCustomJobStatusReader := helmStatusReaders.NewCustomJobStatusReader(w.restMapper)
	customSR := statusreaders.NewStatusReader(w.restMapper, newCustomJobStatusReader)
	sw.StatusReader = customSR
	return w.wait(ctx, resourceList, sw)
}

func (w *statusWaiter) WaitForDelete(resourceList ResourceList, timeout time.Duration) error {
	ctx, cancel := context.WithTimeout(context.TODO(), timeout)
	defer cancel()
	slog.Debug("waiting for resources to be deleted", "count", len(resourceList), "timeout", timeout)
	sw := watcher.NewDefaultStatusWatcher(w.client, w.restMapper)
	return w.waitForDelete(ctx, resourceList, sw)
}

func (w *statusWaiter) waitForDelete(ctx context.Context, resourceList ResourceList, sw watcher.StatusWatcher) error {
	if w.ctx != nil {
		ctx = w.ctx
	}
	cancelCtx, cancel := context.WithCancel(ctx)
	defer cancel()
	resources := []object.ObjMetadata{}
	for _, resource := range resourceList {
		obj, err := object.RuntimeToObjMeta(resource.Object)
		if err != nil {
			return err
		}
		resources = append(resources, obj)
	}
	eventCh := sw.Watch(cancelCtx, resources, watcher.Options{})
	statusCollector := collector.NewResourceStatusCollector(resources)
	done := statusCollector.ListenWithObserver(eventCh, statusObserver(cancel, status.NotFoundStatus))
	<-done

	if statusCollector.Error != nil {
		return statusCollector.Error
	}

	// Only check parent context error, otherwise we would error when desired status is achieved.
	if ctx.Err() != nil {
		errs := []error{}
		for _, id := range resources {

Review comment (refactor):
We should integrate with the `context.WithTimeout(context.TODO(), timeout)` in `WaitForDelete` above (and in other places have similar logic)

```
ctx, cancel := context.WithTimeout(w.ctx, timeout)
```

I could also imagine a helper:
```
func func (w *statusWaiter) contextWithTimeout(timeout time.Duration) (context.Context, context.CancelFunc) {
    ctx := w.ctx
    if ctx == nil {
        ctx = context.TODO()
    }
    
    return context.WithTimeout(ctx, timeout)
}
```

Code after:
	defer cancel()
	slog.Debug("waiting for resources", "count", len(resourceList), "timeout", timeout)
	sw := watcher.NewDefaultStatusWatcher(w.client, w.restMapper)
	return w.wait(ctx, resourceList, sw)
}

func (w *statusWaiter) WaitWithJobs(resourceList ResourceList, timeout time.Duration) error {
	ctx, cancel := w.contextWithTimeout(timeout)
	defer cancel()
	slog.Debug("waiting for resources", "count", len(resourceList), "timeout", timeout)
	sw := watcher.NewDefaultStatusWatcher(w.client, w.restMapper)
	newCustomJobStatusReader := helmStatusReaders.NewCustomJobStatusReader(w.restMapper)
	customSR := statusreaders.NewStatusReader(w.restMapper, newCustomJobStatusReader)
	sw.StatusReader = customSR
	return w.wait(ctx, resourceList, sw)
}

func (w *statusWaiter) WaitForDelete(resourceList ResourceList, timeout time.Duration) error {
	ctx, cancel := w.contextWithTimeout(timeout)
	defer cancel()
	slog.Debug("waiting for resources to be deleted", "count", len(resourceList), "timeout", timeout)
	sw := watcher.NewDefaultStatusWatcher(w.client, w.restMapper)
	return w.waitForDelete(ctx, resourceList, sw)
}

func (w *statusWaiter) waitForDelete(ctx context.Context, resourceList ResourceList, sw watcher.StatusWatcher) error {
	cancelCtx, cancel := context.WithCancel(ctx)
	defer cancel()
	resources := []object.ObjMetadata{}
	for _, resource := range resourceList {
		obj, err := object.RuntimeToObjMeta(resource.Object)
		if err != nil {
			return err
		}
		resources = append(resources, obj)
	}
	eventCh := sw.Watch(cancelCtx, resources, watcher.Options{})
	statusCollector := collector.NewResourceStatusCollector(resources)
	done := statusCollector.ListenWithObserver(eventCh, statusObserver(cancel, status.NotFoundStatus))
	<-done

	if statusCollector.Error != nil {
		return statusCollector.Error
	}

	// Only check parent context error, otherwise we would error when desired status is achieved.
	if ctx.Err() != nil {
		errs := []error{}
		for _, id := range resources {
			rs := statusCollector.ResourceStatuses[id]
			if rs.Status == status.NotFoundStatus {