func (r *ProjectReconciler) getExistingState(project sentryv1alpha1.Project) (*sentry.Project, error) {
	opts := &sentry.ListOptions{}
	var sProjects []sentry.Project
	for {
		projects, resp, err := r.Sentry.Client.Organizations.ListProjects(r.Sentry.Organization, opts)
		if err != nil {
			switch {
			case resp.StatusCode >= 500:
				return nil, retryableError{err}
			default:
				return nil, err
			}
		}
		sProjects = append(sProjects, projects...)
		if !resp.NextPage.Results {
			break
		}
		opts.Cursor = resp.NextPage.Cursor
	}
	for idx, sProject := range sProjects {
		if sProject.ID == project.Status.ID {
			return &sProjects[idx], nil
		}
	}
	return nil, ErrOutOfSync
}
getExistingState retrieves the true state of the resource that exists in Sentry using its constant resource ID, and
returns an ErrOutOfSync error if the resource cannot be found.
package controllers
import (
	"context"
	"errors"
	"fmt"
	"net/http"
	"time"
	"github.com/go-logr/logr"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/predicate"
	sentryv1alpha1 "github.com/jace-ys/sentry-operator/api/v1alpha1"
	"github.com/jace-ys/sentry-operator/pkg/sentry"
)
const (
	ProjectFinalizerName = "finalizers.sentry.kubernetes.jaceys.me/project"
)
type ProjectReconciler struct {
	client.Client
	Log    logr.Logger
	Scheme *runtime.Scheme
	Sentry *Sentry
}
func (r *ProjectReconciler) SetupWithManager(mgr ctrl.Manager) error {
	return ctrl.NewControllerManagedBy(mgr).
		For(&sentryv1alpha1.Project{}).
		WithEventFilter(&predicate.GenerationChangedPredicate{}).
		Complete(r)
}
func (r *ProjectReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
	ctx := context.Background()
	log := r.Log.WithValues("project", req.NamespacedName)
	var project sentryv1alpha1.Project
	if err := r.Get(ctx, req.NamespacedName, &project); err != nil {
		if apierrors.IsNotFound(err) {
			return ctrl.Result{}, nil
		}
		log.Error(err, "failed to fetch Project")
		return ctrl.Result{}, err
	}
	hasFinalizer := containsFinalizer(project.GetFinalizers(), ProjectFinalizerName)
	if project.Status.LastSynced.IsZero() {
		if err := r.handleCreate(ctx, &project, hasFinalizer); err != nil {
			log.Error(err, "failed to create Project")
			return ctrl.Result{}, r.handleError(ctx, &project, err)
		}
		log.Info("successfully created Project")
		return ctrl.Result{}, nil
	}
	existing, err := r.getExistingState(project)
	if err != nil && !errors.Is(err, ErrOutOfSync) {
		log.Error(err, "failed to fetch Sentry project state")
		return ctrl.Result{}, r.handleError(ctx, &project, err)
	}
	if !project.ObjectMeta.DeletionTimestamp.IsZero() {
		if hasFinalizer {
			if err := r.handleDelete(ctx, &project, existing); err != nil {
				log.Error(err, "failed to delete Project")
				return ctrl.Result{}, r.handleError(ctx, &project, err)
			}
		}
		log.Info("successfully deleted Project")
		return ctrl.Result{}, nil
	}
	if errors.Is(err, ErrOutOfSync) {
		if err := r.handleCreate(ctx, &project, hasFinalizer); err != nil {
			log.Error(err, "failed to recreate Project")
			return ctrl.Result{}, r.handleError(ctx, &project, err)
		}
		log.Info("successfully recreated Project")
		return ctrl.Result{}, nil
	}
	if err := r.handleUpdate(ctx, &project, existing); err != nil {
		log.Error(err, "failed to update Project")
		return ctrl.Result{}, r.handleError(ctx, &project, err)
	}
	log.Info("successfully updated Project")
	return ctrl.Result{}, nil
}