4eadc823a9
* Move repository package to apps
* Move operators to grafana/grafana
* Go mod tidy
* Own package by git sync team for now
* Merged
* Do not use settings in local extra
* Remove dependency on webhook extra
* Hack to work around issue with secure contracts
* Sync Go modules
* Revert "Move operators to grafana/grafana"
This reverts commit 9f19b30a2e.
178 lines
6.2 KiB
Go
178 lines
6.2 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
|
|
|
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
|
)
|
|
|
|
// FIXME: the name of the mock is different because there is another generated mock for Repository
|
|
// I don't know how it got generated.
|
|
//
|
|
//go:generate mockery --name Repository --structname MockConfigRepository --inpackage --filename config_repository_mock.go --with-expecter
|
|
type Repository interface {
|
|
// Config returns the saved Kubernetes object.
|
|
Config() *provisioning.Repository
|
|
|
|
// Validate ensures the resource _looks_ correct.
|
|
// It should be called before trying to upsert a resource into the Kubernetes API server.
|
|
// This is not an indication that the connection information works, just that they are reasonably configured (see also Test).
|
|
Validate() field.ErrorList
|
|
|
|
// Test checks if the connection information actually works.
|
|
Test(ctx context.Context) (*provisioning.TestResults, error)
|
|
}
|
|
|
|
// ErrFileNotFound indicates that a path could not be found in the repository.
|
|
var ErrFileNotFound error = &apierrors.StatusError{ErrStatus: metav1.Status{
|
|
Status: metav1.StatusFailure,
|
|
Code: http.StatusNotFound,
|
|
Reason: metav1.StatusReasonNotFound,
|
|
Message: "file not found",
|
|
}}
|
|
|
|
var ErrRefNotFound error = &apierrors.StatusError{ErrStatus: metav1.Status{
|
|
Status: metav1.StatusFailure,
|
|
Code: http.StatusNotFound,
|
|
Reason: metav1.StatusReasonNotFound,
|
|
Message: "ref not found",
|
|
}}
|
|
|
|
var ErrFileAlreadyExists error = &apierrors.StatusError{ErrStatus: metav1.Status{
|
|
Status: metav1.StatusFailure,
|
|
Code: http.StatusConflict,
|
|
Reason: metav1.StatusReasonAlreadyExists,
|
|
Message: "file already exists",
|
|
}}
|
|
|
|
type FileInfo struct {
|
|
// Path to the file on disk.
|
|
// No leading or trailing slashes will be contained within.
|
|
// This uses '/' for separation. Use the 'path' package to interact with this.
|
|
Path string
|
|
// The raw bytes
|
|
Data []byte
|
|
// The git branch or reference commit
|
|
Ref string
|
|
// The git hash for a given file
|
|
Hash string
|
|
// When was the file changed (if known)
|
|
Modified *metav1.Time
|
|
}
|
|
|
|
// An entry in the file tree, as returned by 'ReadFileTree'. Like FileInfo, but contains less information.
|
|
type FileTreeEntry struct {
|
|
// The path to the file from the base path given (if any).
|
|
// No leading or trailing slashes will be contained within.
|
|
// This uses '/' for separation. Use the 'path' package to interact with this.
|
|
Path string
|
|
// The hash for the file. Lower-case hex.
|
|
// Empty string if Blob is false.
|
|
Hash string
|
|
// The size of the file.
|
|
// 0 if Blob is false.
|
|
Size int64
|
|
// Whether this entry is a blob or a subtree.
|
|
Blob bool
|
|
}
|
|
|
|
//go:generate mockery --name Reader --structname MockReader --inpackage --filename reader_mock.go --with-expecter
|
|
type Reader interface {
|
|
Repository
|
|
|
|
// Read a file from the resource
|
|
// This data will be parsed and validated before it is shown to end users
|
|
Read(ctx context.Context, path, ref string) (*FileInfo, error)
|
|
|
|
// Read all file names from the tree.
|
|
// This data will be parsed and validated before it is shown.
|
|
//
|
|
// TODO: Make some API contract that lets us ignore files that aren't relevant to us (e.g. CI/CD, CODEOWNERS, other configs or source code).
|
|
// TODO: Test scale: do we want to stream entries instead somehow?
|
|
ReadTree(ctx context.Context, ref string) ([]FileTreeEntry, error)
|
|
}
|
|
|
|
type Writer interface {
|
|
Repository
|
|
|
|
// Write a file to the repository.
|
|
// The data has already been validated and is ready for save
|
|
Create(ctx context.Context, path, ref string, data []byte, message string) error
|
|
|
|
// Update a file in the remote repository
|
|
// The data has already been validated and is ready for save
|
|
Update(ctx context.Context, path, ref string, data []byte, message string) error
|
|
|
|
// Write a file to the repository.
|
|
// Functionally the same as Read then Create or Update, but more efficient depending on the backend
|
|
Write(ctx context.Context, path, ref string, data []byte, message string) error
|
|
|
|
// Delete a file in the remote repository
|
|
Delete(ctx context.Context, path, ref, message string) error
|
|
|
|
// Move a file from one path to another in the remote repository
|
|
Move(ctx context.Context, oldPath, newPath, ref, message string) error
|
|
}
|
|
|
|
//go:generate mockery --name ReaderWriter --structname MockReaderWriter --inpackage --filename reader_writer_mock.go --with-expecter
|
|
type ReaderWriter interface {
|
|
Reader
|
|
Writer
|
|
}
|
|
|
|
//go:generate mockery --name RepositoryWithURLs --structname MockRepositoryWithURLs --inpackage --filename repository_with_urls_mock.go --with-expecter
|
|
type RepositoryWithURLs interface {
|
|
Repository
|
|
|
|
// Get resource URLs for a file inside a repository
|
|
ResourceURLs(ctx context.Context, file *FileInfo) (*provisioning.RepositoryURLs, error)
|
|
RefURLs(ctx context.Context, ref string) (*provisioning.RepositoryURLs, error)
|
|
}
|
|
|
|
// Hooks called after the repository has been created, updated or deleted
|
|
type Hooks interface {
|
|
Repository
|
|
|
|
OnCreate(ctx context.Context) ([]map[string]interface{}, error)
|
|
OnUpdate(ctx context.Context) ([]map[string]interface{}, error)
|
|
OnDelete(ctx context.Context) error
|
|
}
|
|
|
|
type FileAction string
|
|
|
|
const (
|
|
FileActionCreated FileAction = "created"
|
|
FileActionUpdated FileAction = "updated"
|
|
FileActionDeleted FileAction = "deleted"
|
|
FileActionIgnored FileAction = "ignored"
|
|
|
|
// Renamed actions may be reconstructed as delete then create
|
|
FileActionRenamed FileAction = "renamed"
|
|
)
|
|
|
|
type VersionedFileChange struct {
|
|
Action FileAction
|
|
Path string
|
|
|
|
Ref string
|
|
PreviousRef string // rename | update
|
|
PreviousPath string // rename
|
|
}
|
|
|
|
// Versioned is a repository that supports versioning.
|
|
// This interface may be extended to make the the original Repository interface more agnostic to the underlying storage system.
|
|
//
|
|
//go:generate mockery --name Versioned --structname MockVersioned --inpackage --filename versioned_mock.go --with-expecter
|
|
type Versioned interface {
|
|
// History of changes for a path
|
|
History(ctx context.Context, path, ref string) ([]provisioning.HistoryItem, error)
|
|
LatestRef(ctx context.Context) (string, error)
|
|
ListRefs(ctx context.Context) ([]provisioning.RefItem, error)
|
|
CompareFiles(ctx context.Context, base, ref string) ([]VersionedFileChange, error)
|
|
}
|