Packages now always belong to a repository (#480)

Some groundwork in preparation for #460

Signed-off-by: Sergio Castaño Arteaga <tegioz@icloud.com>
Signed-off-by: Cintia Sanchez Garcia <cynthiasg@icloud.com>
This commit is contained in:
Sergio C. Arteaga 2020-06-24 01:06:07 +02:00 committed by GitHub
parent b330b758a5
commit b4a8635a59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
360 changed files with 7528 additions and 6168 deletions

View File

@ -89,8 +89,8 @@ jobs:
- name: Build hub
working-directory: ./cmd/hub
run: go build -v
- name: Build chart-tracker
working-directory: ./cmd/chart-tracker
- name: Build helm-tracker
working-directory: ./cmd/helm-tracker
run: go build -v
build-frontend:
@ -140,13 +140,13 @@ jobs:
-t $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/db-migrator:$GITHUB_SHA .
- name: Push db-migrator image
run: docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/db-migrator:$GITHUB_SHA
- name: Build chart-tracker image
- name: Build helm-tracker image
run: |
docker build \
-f cmd/chart-tracker/Dockerfile \
-t $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/chart-tracker:$GITHUB_SHA .
- name: Push chart-tracker image
run: docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/chart-tracker:$GITHUB_SHA
-f cmd/helm-tracker/Dockerfile \
-t $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/helm-tracker:$GITHUB_SHA .
- name: Push helm-tracker image
run: docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/helm-tracker:$GITHUB_SHA
deploy-staging:
if: github.ref == 'refs/heads/staging'

View File

@ -30,11 +30,11 @@ jobs:
-t artifacthub/db-migrator:latest .
- name: Push db-migrator image
run: docker push artifacthub/db-migrator
- name: Build chart-tracker image
- name: Build helm-tracker image
run: |
docker build \
-f cmd/chart-tracker/Dockerfile \
-t artifacthub/chart-tracker:${{steps.extract_tag_name.outputs.tag}} \
-t artifacthub/chart-tracker:latest .
- name: Push chart-tracker image
run: docker push artifacthub/chart-tracker
-f cmd/helm-tracker/Dockerfile \
-t artifacthub/helm-tracker:${{steps.extract_tag_name.outputs.tag}} \
-t artifacthub/helm-tracker:latest .
- name: Push helm-tracker image
run: docker push artifacthub/helm-tracker

View File

@ -77,10 +77,10 @@ When the parameter `dbMigrator.loadSampleData` is set to true (default) a **demo
### Populating packages
The chart installs a `cronjob` in charge of launching periodically (every 30m) a process called `chart-tracker` which indexes charts. If you don't want to wait until it's triggered by the cronjob, you can create a `job` manually using the following command:
The chart installs a `cronjob` in charge of launching periodically (every 30m) a process called `helm-tracker` which indexes Helm charts. If you don't want to wait until it's triggered by the cronjob, you can create a `job` manually using the following command:
```bash
$ kubectl create job initial-chart-tracker-job --from=cronjob/chart-tracker
$ kubectl create job initial-helm-tracker-job --from=cronjob/helm-tracker
```
### Uninstalling the Chart

View File

@ -29,10 +29,10 @@ When the parameter `dbMigrator.loadSampleData` is set to true (default) a **demo
## Populating packages
The chart installs a `cronjob` in charge of launching periodically (every 30m) a process called `chart-tracker` which indexes charts. If you don't want to wait until it's triggered by the cronjob, you can create a `job` manually using the following command:
The chart installs a `cronjob` in charge of launching periodically (every 30m) a process called `helm-tracker` which indexes Helm charts. If you don't want to wait until it's triggered by the cronjob, you can create a `job` manually using the following command:
```bash
$ kubectl create job initial-chart-tracker-job --from=cronjob/chart-tracker
$ kubectl create job initial-helm-tracker-job --from=cronjob/helm-tracker
```
## Uninstalling the Chart
@ -49,58 +49,58 @@ The command removes all the Kubernetes components associated with the chart and
The following table lists the configurable parameters of the Artifact Hub chart and their default values.
| Parameter | Description | Default |
| --------------------------------------- | --------------------------------- | ------------------------------------------ |
| `imageTag` | Tag used when pulling images | `latest` |
| `pullPolicy` | Image pull policy | `IfNotPresent` |
| `log.level` | Log level | `info` |
| `log.pretty` | Enable pretty logging | `false` |
| `db.host` | Database host | `hub-postgresql.default.svc.cluster.local` |
| `db.port` | Database port | `5432` |
| `db.database` | Database name | `hub` |
| `db.user` | Database user | `postgres` |
| `db.password` | Database password | `postgres` |
| `hub.ingress.enabled` | Enable Hub ingress | `true` |
| `hub.ingress.annotations` | Hub ingress annotations | `{kubernetes.io/ingress.class: nginx}` |
| `hub.service.type` | Hub service type | `NodePort` |
| `hub.service.port` | Hub service port | 80 |
| `hub.deploy.replicaCount` | Hub replicas | 1 |
| `hub.deploy.image.repository` | Hub image repository | `artifacthub/hub` |
| `hub.deploy.resources` | Hub requested resources | Memory: `500Mi`, CPU: `100m` |
| `hub.server.baseURL` | Hub server base url | |
| `hub.server.basicAuth.enabled` | Enable basic auth | `false` |
| `hub.server.basicAuth.username` | Hub basic auth username | `hub` |
| `hub.server.basicAuth.password` | Hub basic auth password | `changeme` |
| `hub.server.cookie.hashKey` | Hub cookie hash key | `default-unsafe-key` |
| `hub.server.cookie.secure` | Enable Hub secure cookies | `false` |
| `hub.server.oauth.github.clientID` | Github oauth client id | |
| `hub.server.oauth.github.clientSecret` | Github oauth client secret | |
| `hub.server.oauth.github.redirectURL` | Github oauth redirect url | |
| `hub.server.oauth.github.scopes` | Github oauth scopes | `[read:user, user:email]` |
| `hub.server.oauth.google.clientID` | Google oauth client id | |
| `hub.server.oauth.google.clientSecret` | Google oauth client secret | |
| `hub.server.oauth.google.redirectURL` | Google oauth redirect url | |
| `hub.server.oauth.google.scopes` | Google oauth scopes | `[userinfo.email, userinfo.profile]` |
| `hub.server.limiter.enabled` | Enable rate limiter | `false` |
| `hub.server.limiter.period` | Rate limiter period (1m, etc) | |
| `hub.server.limiter.limit` | Rate limiter limit (reqs/period) | |
| `hub.server.xffIndex` | X-Forwarded-For IP index | 0 |
| `hub.email.fromName` | From name used in emails | |
| `hub.email.from` | From address used in emails | |
| `hub.email.replyTo` | Reply-to address used in emails | |
| `hub.email.smtp.host` | SMTP host | |
| `hub.email.smtp.port` | SMTP port | 587 |
| `hub.email.smtp.username` | SMTP username | |
| `hub.email.smtp.password` | SMTP password | |
| `hub.analytics.gaTrackingID` | Google Analytics tracking id | |
| `chartTracker.cronjob.image.repository` | Chart tracker image repository | `artifacthub/chart-tracker` |
| `chartTracker.cronjob.resources` | Chart tracker requested resources | Memory: `500Mi`, CPU: `100m` |
| `chartTracker.numWorkers` | Chart tracker number of workers | 50 |
| `chartTracker.repositories` | Repos names to process ([] = all) | [] |
| `chartTracker.imageStore` | Image store | `pg` |
| `chartTracker.bypassDigestCheck` | Bypass digest check | `false` |
| `dbMigrator.job.image.repository` | DB migrator image repository | `artifacthub/db-migrator` |
| `dbMigrator.loadSampleData` | Load demo user and sample repos | `true` |
| Parameter | Description | Default |
| -------------------------------------- | --------------------------------- | ------------------------------------------ |
| `imageTag` | Tag used when pulling images | `latest` |
| `pullPolicy` | Image pull policy | `IfNotPresent` |
| `log.level` | Log level | `info` |
| `log.pretty` | Enable pretty logging | `false` |
| `db.host` | Database host | `hub-postgresql.default.svc.cluster.local` |
| `db.port` | Database port | `5432` |
| `db.database` | Database name | `hub` |
| `db.user` | Database user | `postgres` |
| `db.password` | Database password | `postgres` |
| `hub.ingress.enabled` | Enable Hub ingress | `true` |
| `hub.ingress.annotations` | Hub ingress annotations | `{kubernetes.io/ingress.class: nginx}` |
| `hub.service.type` | Hub service type | `NodePort` |
| `hub.service.port` | Hub service port | 80 |
| `hub.deploy.replicaCount` | Hub replicas | 1 |
| `hub.deploy.image.repository` | Hub image repository | `artifacthub/hub` |
| `hub.deploy.resources` | Hub requested resources | Memory: `500Mi`, CPU: `100m` |
| `hub.server.baseURL` | Hub server base url | |
| `hub.server.basicAuth.enabled` | Enable basic auth | `false` |
| `hub.server.basicAuth.username` | Hub basic auth username | `hub` |
| `hub.server.basicAuth.password` | Hub basic auth password | `changeme` |
| `hub.server.cookie.hashKey` | Hub cookie hash key | `default-unsafe-key` |
| `hub.server.cookie.secure` | Enable Hub secure cookies | `false` |
| `hub.server.oauth.github.clientID` | Github oauth client id | |
| `hub.server.oauth.github.clientSecret` | Github oauth client secret | |
| `hub.server.oauth.github.redirectURL` | Github oauth redirect url | |
| `hub.server.oauth.github.scopes` | Github oauth scopes | `[read:user, user:email]` |
| `hub.server.oauth.google.clientID` | Google oauth client id | |
| `hub.server.oauth.google.clientSecret` | Google oauth client secret | |
| `hub.server.oauth.google.redirectURL` | Google oauth redirect url | |
| `hub.server.oauth.google.scopes` | Google oauth scopes | `[userinfo.email, userinfo.profile]` |
| `hub.server.limiter.enabled` | Enable rate limiter | `false` |
| `hub.server.limiter.period` | Rate limiter period (1m, etc) | |
| `hub.server.limiter.limit` | Rate limiter limit (reqs/period) | |
| `hub.server.xffIndex` | X-Forwarded-For IP index | 0 |
| `hub.email.fromName` | From name used in emails | |
| `hub.email.from` | From address used in emails | |
| `hub.email.replyTo` | Reply-to address used in emails | |
| `hub.email.smtp.host` | SMTP host | |
| `hub.email.smtp.port` | SMTP port | 587 |
| `hub.email.smtp.username` | SMTP username | |
| `hub.email.smtp.password` | SMTP password | |
| `hub.analytics.gaTrackingID` | Google Analytics tracking id | |
| `helmTracker.cronjob.image.repository` | Helm tracker image repository | `artifacthub/helm-tracker` |
| `helmTracker.cronjob.resources` | Helm tracker requested resources | Memory: `500Mi`, CPU: `100m` |
| `helmTracker.numWorkers` | Helm tracker number of workers | 50 |
| `helmTracker.repositories` | Repos names to process ([] = all) | [] |
| `helmTracker.imageStore` | Image store | `pg` |
| `helmTracker.bypassDigestCheck` | Bypass digest check | `false` |
| `dbMigrator.job.image.repository` | DB migrator image repository | `artifacthub/db-migrator` |
| `dbMigrator.loadSampleData` | Load demo user and sample repos | `true` |
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,

View File

@ -1,7 +1,7 @@
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: chart-tracker
name: helm-tracker
spec:
schedule: "*/30 * * * *"
successfulJobsHistoryLimit: 1
@ -20,7 +20,7 @@ spec:
image: {{ .Values.postgresql.image.repository }}:{{ .Values.postgresql.image.tag }}
imagePullPolicy: {{ .Values.pullPolicy }}
resources:
{{- toYaml .Values.chartTracker.cronjob.resources | nindent 14 }}
{{- toYaml .Values.helmTracker.cronjob.resources | nindent 14 }}
env:
- name: PGHOST
value: {{ .Values.db.host }}
@ -28,14 +28,14 @@ spec:
value: "{{ .Values.db.port }}"
command: ['sh', '-c', 'until pg_isready; do echo waiting for database; sleep 2; done;']
containers:
- name: chart-tracker
image: {{ .Values.chartTracker.cronjob.image.repository }}:{{ .Values.imageTag }}
- name: helm-tracker
image: {{ .Values.helmTracker.cronjob.image.repository }}:{{ .Values.imageTag }}
imagePullPolicy: {{ .Values.pullPolicy }}
volumeMounts:
- name: chart-tracker-config
mountPath: "/home/chart-tracker/.cfg"
- name: helm-tracker-config
mountPath: "/home/helm-tracker/.cfg"
readOnly: true
volumes:
- name: chart-tracker-config
- name: helm-tracker-config
secret:
secretName: chart-tracker-config
secretName: helm-tracker-config

View File

@ -1,10 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: chart-tracker-config
name: helm-tracker-config
type: Opaque
stringData:
chart-tracker.yaml: |-
helm-tracker.yaml: |-
log:
level: {{ .Values.log.level }}
pretty: {{ .Values.log.pretty }}
@ -15,7 +15,7 @@ stringData:
user: {{ .Values.db.user }}
password: {{ .Values.db.password }}
tracker:
numWorkers: {{ .Values.chartTracker.numWorkers }}
repositoriesNames: {{ .Values.chartTracker.repositories }}
imageStore: {{ .Values.chartTracker.imageStore }}
bypassDigestCheck: {{ .Values.chartTracker.bypassDigestCheck }}
numWorkers: {{ .Values.helmTracker.numWorkers }}
repositoriesNames: {{ .Values.helmTracker.repositories }}
imageStore: {{ .Values.helmTracker.imageStore }}
bypassDigestCheck: {{ .Values.helmTracker.bypassDigestCheck }}

View File

@ -45,7 +45,7 @@ hub:
google:
redirectURL: https://artifacthub.io/oauth/google/callback
chartTracker:
helmTracker:
cronjob:
resources:
requests:

View File

@ -46,7 +46,7 @@ hub:
google:
redirectURL: https://staging.artifacthub.io/oauth/google/callback
chartTracker:
helmTracker:
cronjob:
resources:
requests:

View File

@ -70,10 +70,10 @@ hub:
analytics:
gaTrackingID: ""
chartTracker:
helmTracker:
cronjob:
image:
repository: artifacthub/chart-tracker
repository: artifacthub/helm-tracker
resources:
requests:
cpu: 100m

View File

@ -1,15 +0,0 @@
# Build chart-tracker
FROM golang:1.14-alpine AS builder
WORKDIR /go/src/github.com/artifacthub/hub
COPY go.* ./
COPY cmd/chart-tracker cmd/chart-tracker
COPY internal internal
RUN cd cmd/chart-tracker && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /chart-tracker .
# Final stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates && addgroup -S chart-tracker && adduser -S chart-tracker -G chart-tracker
USER chart-tracker
WORKDIR /home/chart-tracker
COPY --from=builder /chart-tracker ./
CMD ["./chart-tracker"]

View File

@ -0,0 +1,15 @@
# Build helm-tracker
FROM golang:1.14-alpine AS builder
WORKDIR /go/src/github.com/artifacthub/hub
COPY go.* ./
COPY cmd/helm-tracker cmd/helm-tracker
COPY internal internal
RUN cd cmd/helm-tracker && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /helm-tracker .
# Final stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates && addgroup -S helm-tracker && adduser -S helm-tracker -G helm-tracker
USER helm-tracker
WORKDIR /home/helm-tracker
COPY --from=builder /helm-tracker ./
CMD ["./helm-tracker"]

View File

@ -32,7 +32,7 @@ const (
// dispatcher and will eventually be handled by a worker.
type Job struct {
Kind JobKind
Repo *hub.ChartRepository
Repo *hub.Repository
ChartVersion *repo.ChartVersion
GetLogo bool
}
@ -42,8 +42,8 @@ type Job struct {
type Dispatcher struct {
ctx context.Context
cfg *viper.Viper
il hub.ChartRepositoryIndexLoader
rm hub.ChartRepositoryManager
il hub.HelmIndexLoader
rm hub.RepositoryManager
ec ErrorsCollector
Queue chan *Job
}
@ -52,8 +52,8 @@ type Dispatcher struct {
func NewDispatcher(
ctx context.Context,
cfg *viper.Viper,
il hub.ChartRepositoryIndexLoader,
rm hub.ChartRepositoryManager,
il hub.HelmIndexLoader,
rm hub.RepositoryManager,
ec ErrorsCollector,
) *Dispatcher {
return &Dispatcher{
@ -67,7 +67,7 @@ func NewDispatcher(
}
// Run instructs the dispatcher to start processing the repositories provided.
func (d *Dispatcher) Run(wg *sync.WaitGroup, repos []*hub.ChartRepository) {
func (d *Dispatcher) Run(wg *sync.WaitGroup, repos []*hub.Repository) {
defer wg.Done()
defer close(d.Queue)
@ -87,20 +87,20 @@ func (d *Dispatcher) Run(wg *sync.WaitGroup, repos []*hub.ChartRepository) {
// generateSyncJobs generates the jobs to register or unregister chart releases
// as needed to keep them in sync.
func (d *Dispatcher) generateSyncJobs(wg *sync.WaitGroup, r *hub.ChartRepository) {
func (d *Dispatcher) generateSyncJobs(wg *sync.WaitGroup, r *hub.Repository) {
defer wg.Done()
log.Info().Str("repo", r.Name).Msg("loading chart repository index file")
log.Info().Str("repo", r.Name).Msg("loading repository index file")
indexFile, err := d.il.LoadIndex(r)
if err != nil {
msg := "error loading repository index file"
d.ec.Append(r.ChartRepositoryID, fmt.Errorf("%s: %w", msg, err))
d.ec.Append(r.RepositoryID, fmt.Errorf("%s: %w", msg, err))
log.Error().Err(err).Str("repo", r.Name).Msg(msg)
return
}
log.Info().Str("repo", r.Name).Msg("loading registered packages digest")
registeredPackagesDigest, err := d.rm.GetPackagesDigest(d.ctx, r.ChartRepositoryID)
registeredPackagesDigest, err := d.rm.GetPackagesDigest(d.ctx, r.RepositoryID)
if err != nil {
log.Error().Err(err).Str("repo", r.Name).Msg("error getting repository packages digest")
return

View File

@ -6,13 +6,13 @@ import (
"sync"
"testing"
"github.com/artifacthub/hub/internal/chartrepo"
"github.com/artifacthub/hub/internal/hub"
"github.com/artifacthub/hub/internal/repo"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/repo"
helmrepo "helm.sh/helm/v3/pkg/repo"
)
func TestDispatcher(t *testing.T) {
@ -23,64 +23,64 @@ func TestDispatcher(t *testing.T) {
dw := newDispatcherWrapper(ctx)
// Run dispatcher and check expectations
r := &hub.ChartRepository{ChartRepositoryID: "repo1"}
dw.d.Run(dw.wg, []*hub.ChartRepository{r})
r := &hub.Repository{RepositoryID: "repo1"}
dw.d.Run(dw.wg, []*hub.Repository{r})
dw.assertExpectations(t, nil)
})
t.Run("error loading chart repository index file", func(t *testing.T) {
// Setup dispatcher and expectations
r := &hub.ChartRepository{ChartRepositoryID: "repo1"}
r := &hub.Repository{RepositoryID: "repo1"}
dw := newDispatcherWrapper(context.Background())
dw.il.On("LoadIndex", r).Return(nil, errFake)
dw.ec.On("Append", r.ChartRepositoryID, mock.Anything).Return()
dw.ec.On("Append", r.RepositoryID, mock.Anything).Return()
// Run dispatcher and check expectations
dw.d.Run(dw.wg, []*hub.ChartRepository{r})
dw.d.Run(dw.wg, []*hub.Repository{r})
dw.assertExpectations(t, nil)
})
t.Run("error loading registered packages digest", func(t *testing.T) {
// Setup dispatcher and expectations
r := &hub.ChartRepository{ChartRepositoryID: "repo1"}
r := &hub.Repository{RepositoryID: "repo1"}
dw := newDispatcherWrapper(context.Background())
dw.il.On("LoadIndex", r).Return(nil, nil)
dw.rm.On("GetPackagesDigest", dw.d.ctx, r.ChartRepositoryID).Return(nil, errFake)
dw.rm.On("GetPackagesDigest", dw.d.ctx, r.RepositoryID).Return(nil, errFake)
// Run dispatcher and check expectations
dw.d.Run(dw.wg, []*hub.ChartRepository{r})
dw.d.Run(dw.wg, []*hub.Repository{r})
dw.assertExpectations(t, nil)
})
t.Run("dispatcher completed successfully", func(t *testing.T) {
repo1 := &hub.ChartRepository{
ChartRepositoryID: "repo1",
repo1 := &hub.Repository{
RepositoryID: "repo1",
}
repo2 := &hub.ChartRepository{
ChartRepositoryID: "repo2",
repo2 := &hub.Repository{
RepositoryID: "repo2",
}
pkg1V1 := &repo.ChartVersion{
pkg1V1 := &helmrepo.ChartVersion{
Metadata: &chart.Metadata{
Name: "pkg1",
Version: "1.0.0",
},
Digest: "pkg1-1.0.0",
}
pkg1V2 := &repo.ChartVersion{
pkg1V2 := &helmrepo.ChartVersion{
Metadata: &chart.Metadata{
Name: "pkg1",
Version: "2.0.0",
},
Digest: "pkg1-2.0.0",
}
pkg2V1 := &repo.ChartVersion{
pkg2V1 := &helmrepo.ChartVersion{
Metadata: &chart.Metadata{
Name: "pkg2",
Version: "1.0.0",
},
Digest: "pkg2-1.0.0",
}
pkg3V1 := &repo.ChartVersion{
pkg3V1 := &helmrepo.ChartVersion{
Metadata: &chart.Metadata{
Name: "pkg3",
Version: "1.0.0",
@ -90,20 +90,20 @@ func TestDispatcher(t *testing.T) {
testCases := []struct {
n int
repos []*hub.ChartRepository
indexFile map[string]*repo.IndexFile
repos []*hub.Repository
indexFile map[string]*helmrepo.IndexFile
packagesDigest map[string]map[string]string
expectedJobs []*Job
}{
{
1,
[]*hub.ChartRepository{
[]*hub.Repository{
repo1,
},
map[string]*repo.IndexFile{
map[string]*helmrepo.IndexFile{
"repo1": {
Entries: map[string]repo.ChartVersions{
"pkg1": []*repo.ChartVersion{
Entries: map[string]helmrepo.ChartVersions{
"pkg1": []*helmrepo.ChartVersion{
pkg1V1,
},
},
@ -121,13 +121,13 @@ func TestDispatcher(t *testing.T) {
},
{
2,
[]*hub.ChartRepository{
[]*hub.Repository{
repo1,
},
map[string]*repo.IndexFile{
map[string]*helmrepo.IndexFile{
"repo1": {
Entries: map[string]repo.ChartVersions{
"pkg1": []*repo.ChartVersion{
Entries: map[string]helmrepo.ChartVersions{
"pkg1": []*helmrepo.ChartVersion{
pkg1V1,
pkg1V2,
},
@ -152,13 +152,13 @@ func TestDispatcher(t *testing.T) {
},
{
3,
[]*hub.ChartRepository{
[]*hub.Repository{
repo1,
},
map[string]*repo.IndexFile{
map[string]*helmrepo.IndexFile{
"repo1": {
Entries: map[string]repo.ChartVersions{
"pkg1": []*repo.ChartVersion{
Entries: map[string]helmrepo.ChartVersions{
"pkg1": []*helmrepo.ChartVersion{
pkg1V1,
},
},
@ -173,13 +173,13 @@ func TestDispatcher(t *testing.T) {
},
{
4,
[]*hub.ChartRepository{
[]*hub.Repository{
repo1,
},
map[string]*repo.IndexFile{
map[string]*helmrepo.IndexFile{
"repo1": {
Entries: map[string]repo.ChartVersions{
"pkg1": []*repo.ChartVersion{
Entries: map[string]helmrepo.ChartVersions{
"pkg1": []*helmrepo.ChartVersion{
pkg1V1,
pkg1V2,
},
@ -196,13 +196,13 @@ func TestDispatcher(t *testing.T) {
},
{
5,
[]*hub.ChartRepository{
[]*hub.Repository{
repo1,
},
map[string]*repo.IndexFile{
map[string]*helmrepo.IndexFile{
"repo1": {
Entries: map[string]repo.ChartVersions{
"pkg1": []*repo.ChartVersion{
Entries: map[string]helmrepo.ChartVersions{
"pkg1": []*helmrepo.ChartVersion{
pkg1V1,
pkg1V2,
},
@ -226,17 +226,17 @@ func TestDispatcher(t *testing.T) {
},
{
6,
[]*hub.ChartRepository{
[]*hub.Repository{
repo1,
},
map[string]*repo.IndexFile{
map[string]*helmrepo.IndexFile{
"repo1": {
Entries: map[string]repo.ChartVersions{
"pkg1": []*repo.ChartVersion{
Entries: map[string]helmrepo.ChartVersions{
"pkg1": []*helmrepo.ChartVersion{
pkg1V1,
pkg1V2,
},
"pkg2": []*repo.ChartVersion{
"pkg2": []*helmrepo.ChartVersion{
pkg2V1,
},
},
@ -259,25 +259,25 @@ func TestDispatcher(t *testing.T) {
},
{
7,
[]*hub.ChartRepository{
[]*hub.Repository{
repo1,
repo2,
},
map[string]*repo.IndexFile{
map[string]*helmrepo.IndexFile{
"repo1": {
Entries: map[string]repo.ChartVersions{
"pkg1": []*repo.ChartVersion{
Entries: map[string]helmrepo.ChartVersions{
"pkg1": []*helmrepo.ChartVersion{
pkg1V1,
pkg1V2,
},
"pkg2": []*repo.ChartVersion{
"pkg2": []*helmrepo.ChartVersion{
pkg2V1,
},
},
},
"repo2": {
Entries: map[string]repo.ChartVersions{
"pkg3": []*repo.ChartVersion{
Entries: map[string]helmrepo.ChartVersions{
"pkg3": []*helmrepo.ChartVersion{
pkg3V1,
},
},
@ -313,10 +313,10 @@ func TestDispatcher(t *testing.T) {
},
{
8,
[]*hub.ChartRepository{
[]*hub.Repository{
repo1,
},
map[string]*repo.IndexFile{
map[string]*helmrepo.IndexFile{
"repo1": {
Entries: nil,
},
@ -330,7 +330,7 @@ func TestDispatcher(t *testing.T) {
{
Kind: Unregister,
Repo: repo1,
ChartVersion: &repo.ChartVersion{
ChartVersion: &helmrepo.ChartVersion{
Metadata: &chart.Metadata{
Name: "pkg1",
Version: "1.0.0",
@ -341,13 +341,13 @@ func TestDispatcher(t *testing.T) {
},
{
9,
[]*hub.ChartRepository{
[]*hub.Repository{
repo1,
},
map[string]*repo.IndexFile{
map[string]*helmrepo.IndexFile{
"repo1": {
Entries: map[string]repo.ChartVersions{
"pkg1": []*repo.ChartVersion{
Entries: map[string]helmrepo.ChartVersions{
"pkg1": []*helmrepo.ChartVersion{
pkg1V2,
},
"pkg2": nil,
@ -365,7 +365,7 @@ func TestDispatcher(t *testing.T) {
{
Kind: Unregister,
Repo: repo1,
ChartVersion: &repo.ChartVersion{
ChartVersion: &helmrepo.ChartVersion{
Metadata: &chart.Metadata{
Name: "pkg1",
Version: "1.0.0",
@ -375,7 +375,7 @@ func TestDispatcher(t *testing.T) {
{
Kind: Unregister,
Repo: repo1,
ChartVersion: &repo.ChartVersion{
ChartVersion: &helmrepo.ChartVersion{
Metadata: &chart.Metadata{
Name: "pkg2",
Version: "1.0.0",
@ -386,23 +386,23 @@ func TestDispatcher(t *testing.T) {
},
{
10,
[]*hub.ChartRepository{
[]*hub.Repository{
repo1,
repo2,
},
map[string]*repo.IndexFile{
map[string]*helmrepo.IndexFile{
"repo1": {
Entries: map[string]repo.ChartVersions{
"pkg1": []*repo.ChartVersion{
Entries: map[string]helmrepo.ChartVersions{
"pkg1": []*helmrepo.ChartVersion{
pkg1V1,
},
"pkg2": []*repo.ChartVersion{
"pkg2": []*helmrepo.ChartVersion{
pkg2V1,
},
},
},
"repo2": {
Entries: map[string]repo.ChartVersions{
Entries: map[string]helmrepo.ChartVersions{
"pkg3": nil,
},
},
@ -421,7 +421,7 @@ func TestDispatcher(t *testing.T) {
{
Kind: Unregister,
Repo: repo1,
ChartVersion: &repo.ChartVersion{
ChartVersion: &helmrepo.ChartVersion{
Metadata: &chart.Metadata{
Name: "pkg1",
Version: "2.0.0",
@ -431,7 +431,7 @@ func TestDispatcher(t *testing.T) {
{
Kind: Unregister,
Repo: repo2,
ChartVersion: &repo.ChartVersion{
ChartVersion: &helmrepo.ChartVersion{
Metadata: &chart.Metadata{
Name: "pkg3",
Version: "1.0.0",
@ -447,9 +447,9 @@ func TestDispatcher(t *testing.T) {
// Setup dispatcher and expectations
dw := newDispatcherWrapper(context.Background())
for _, r := range tc.repos {
dw.il.On("LoadIndex", r).Return(tc.indexFile[r.ChartRepositoryID], nil)
dw.rm.On("GetPackagesDigest", dw.d.ctx, r.ChartRepositoryID).
Return(tc.packagesDigest[r.ChartRepositoryID], nil)
dw.il.On("LoadIndex", r).Return(tc.indexFile[r.RepositoryID], nil)
dw.rm.On("GetPackagesDigest", dw.d.ctx, r.RepositoryID).
Return(tc.packagesDigest[r.RepositoryID], nil)
}
// Run dispatcher and check expectations
@ -463,8 +463,8 @@ func TestDispatcher(t *testing.T) {
type dispatcherWrapper struct {
cfg *viper.Viper
wg *sync.WaitGroup
il *chartrepo.IndexLoaderMock
rm *chartrepo.ManagerMock
il *repo.HelmIndexLoaderMock
rm *repo.ManagerMock
ec *ErrorsCollectorMock
d *Dispatcher
queuedJobs *[]*Job
@ -473,8 +473,8 @@ type dispatcherWrapper struct {
func newDispatcherWrapper(ctx context.Context) *dispatcherWrapper {
// Setup dispatcher
cfg := viper.New()
il := &chartrepo.IndexLoaderMock{}
rm := &chartrepo.ManagerMock{}
il := &repo.HelmIndexLoaderMock{}
rm := &repo.ManagerMock{}
ec := &ErrorsCollectorMock{}
d := NewDispatcher(ctx, cfg, il, rm, ec)

View File

@ -13,66 +13,66 @@ import (
// ErrorsCollector interface defines the methods that an errors collector
// implementation should provide.
type ErrorsCollector interface {
Append(chartRepositoryID string, err error)
Append(repositoryID string, err error)
Flush()
}
const (
// maxErrorsPerChartRepository represents the maximum number of errors we
// want to collect for a given chart repository.
maxErrorsPerChartRepository = 100
// maxErrorsPerRepository represents the maximum number of errors we want
// to collect for a given repository.
maxErrorsPerRepository = 100
)
// DBErrorsCollector is in charge of collecting errors that happen while chart
// DBErrorsCollector is in charge of collecting errors that happen while
// repositories are being processed. Once all the processing is done, the
// collected errors can be flushed, which will store them in the database.
type DBErrorsCollector struct {
ctx context.Context
chartRepoManager hub.ChartRepositoryManager
ctx context.Context
repoManager hub.RepositoryManager
mu sync.Mutex
errors map[string][]error // K: chart repository id
errors map[string][]error // K: repository id
}
// NewDBErrorsCollector creates a new DBErrorsCollector instance.
func NewDBErrorsCollector(
ctx context.Context,
chartRepoManager hub.ChartRepositoryManager,
repos []*hub.ChartRepository,
repoManager hub.RepositoryManager,
repos []*hub.Repository,
) *DBErrorsCollector {
ec := &DBErrorsCollector{
ctx: ctx,
chartRepoManager: chartRepoManager,
errors: make(map[string][]error),
ctx: ctx,
repoManager: repoManager,
errors: make(map[string][]error),
}
for _, r := range repos {
ec.errors[r.ChartRepositoryID] = nil
ec.errors[r.RepositoryID] = nil
}
return ec
}
// Append adds the error provided to the chart repository's list of errors.
func (c *DBErrorsCollector) Append(chartRepositoryID string, err error) {
// Append adds the error provided to the repository's list of errors.
func (c *DBErrorsCollector) Append(repositoryID string, err error) {
c.mu.Lock()
defer c.mu.Unlock()
if len(c.errors[chartRepositoryID]) < maxErrorsPerChartRepository {
c.errors[chartRepositoryID] = append(c.errors[chartRepositoryID], err)
if len(c.errors[repositoryID]) < maxErrorsPerRepository {
c.errors[repositoryID] = append(c.errors[repositoryID], err)
}
}
// Flush aggregates all errors collected per chart repository as a single text
// and stores it in the database.
// Flush aggregates all errors collected per repository as a single text and
// stores it in the database.
func (c *DBErrorsCollector) Flush() {
for chartRepositoryID, errors := range c.errors {
for repositoryID, errors := range c.errors {
var errStr strings.Builder
for _, err := range errors {
errStr.WriteString(err.Error())
errStr.WriteString("\n")
}
err := c.chartRepoManager.SetLastTrackingResults(c.ctx, chartRepositoryID, errStr.String())
err := c.repoManager.SetLastTrackingResults(c.ctx, repositoryID, errStr.String())
if err != nil {
log.Error().Err(err).Str("repoID", chartRepositoryID).Send()
log.Error().Err(err).Str("repoID", repositoryID).Send()
}
}
}
@ -83,8 +83,8 @@ type ErrorsCollectorMock struct {
}
// Append implements the ErrorsCollector interface.
func (m *ErrorsCollectorMock) Append(chartRepositoryID string, err error) {
m.Called(chartRepositoryID, err)
func (m *ErrorsCollectorMock) Append(repositoryID string, err error) {
m.Called(repositoryID, err)
}
// Flush implements the ErrorsCollector interface.

View File

@ -10,9 +10,9 @@ import (
"syscall"
"time"
"github.com/artifacthub/hub/internal/chartrepo"
"github.com/artifacthub/hub/internal/hub"
"github.com/artifacthub/hub/internal/pkg"
"github.com/artifacthub/hub/internal/repo"
"github.com/artifacthub/hub/internal/util"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
@ -20,26 +20,26 @@ import (
func main() {
// Setup configuration and logger
cfg, err := util.SetupConfig("chart-tracker")
cfg, err := util.SetupConfig("helm-tracker")
if err != nil {
log.Fatal().Err(err).Msg("configuration setup failed")
}
fields := map[string]interface{}{
"cmd": "chart-tracker",
"cmd": "helm-tracker",
}
if err := util.SetupLogger(cfg, fields); err != nil {
log.Fatal().Err(err).Msg("logger setup failed")
}
// Shutdown gracefully when SIGINT or SIGTERM signal is received
log.Info().Int("pid", os.Getpid()).Msg("chart tracker started")
log.Info().Int("pid", os.Getpid()).Msg("helm tracker started")
ctx, cancel := context.WithCancel(context.Background())
shutdown := make(chan os.Signal, 1)
signal.Notify(shutdown, os.Interrupt, syscall.SIGTERM)
go func() {
<-shutdown
cancel()
log.Info().Msg("chart tracker shutting down..")
log.Info().Msg("helm tracker shutting down..")
}()
// Setup internal services required
@ -47,16 +47,16 @@ func main() {
if err != nil {
log.Fatal().Err(err).Msg("database setup failed")
}
il := &chartrepo.IndexLoader{}
rm := chartrepo.NewManager(db)
il := &repo.HelmIndexLoader{}
rm := repo.NewManager(db)
pm := pkg.NewManager(db)
is, err := util.SetupImageStore(cfg, db)
if err != nil {
log.Fatal().Err(err).Msg("image store setup failed")
}
// Get chart repositories to process
repos, err := getChartRepositories(cfg, rm)
// Get repositories to process
repos, err := getRepositories(cfg, rm)
if err != nil {
log.Fatal().Err(err).Send()
}
@ -75,27 +75,27 @@ func main() {
}
wg.Wait()
ec.Flush()
log.Info().Msg("chart tracker finished")
log.Info().Msg("helm tracker finished")
}
// getChartRepositories gets the details of the chart repositories the chart
// tracker will process.
func getChartRepositories(cfg *viper.Viper, rm hub.ChartRepositoryManager) ([]*hub.ChartRepository, error) {
// getRepositories gets the details of the repositories the helm tracker will
// process.
func getRepositories(cfg *viper.Viper, rm hub.RepositoryManager) ([]*hub.Repository, error) {
reposNames := cfg.GetStringSlice("tracker.repositoriesNames")
var repos []*hub.ChartRepository
var repos []*hub.Repository
if len(reposNames) > 0 {
for _, name := range reposNames {
repo, err := rm.GetByName(context.Background(), name)
if err != nil {
return nil, fmt.Errorf("error getting chart repository %s: %w", name, err)
return nil, fmt.Errorf("error getting helm repository %s: %w", name, err)
}
repos = append(repos, repo)
}
} else {
var err error
repos, err = rm.GetAll(context.Background())
repos, err = rm.GetByKind(context.Background(), hub.Helm)
if err != nil {
return nil, fmt.Errorf("error getting all chart repositories: %w", err)
return nil, fmt.Errorf("error getting all repositories: %w", err)
}
}
return repos, nil

View File

Before

Width:  |  Height:  |  Size: 85 B

After

Width:  |  Height:  |  Size: 85 B

View File

@ -144,7 +144,7 @@ func (w *Worker) handleRegisterJob(j *Job) error {
if _, err := url.ParseRequestURI(u); err != nil {
tmp, err := url.Parse(j.Repo.URL)
if err != nil {
w.ec.Append(j.Repo.ChartRepositoryID, fmt.Errorf("invalid chart url: %s", u))
w.ec.Append(j.Repo.RepositoryID, fmt.Errorf("invalid chart url: %s", u))
w.logger.Error().Str("url", u).Msg("invalid url")
return err
}
@ -155,7 +155,7 @@ func (w *Worker) handleRegisterJob(j *Job) error {
// Load chart from remote archive
chart, err := w.loadChart(u)
if err != nil {
w.ec.Append(j.Repo.ChartRepositoryID, fmt.Errorf("error loading chart %s: %w", u, err))
w.ec.Append(j.Repo.RepositoryID, fmt.Errorf("error loading chart %s: %w", u, err))
w.logger.Warn().
Str("repo", j.Repo.Name).
Str("chart", j.ChartVersion.Metadata.Name).
@ -173,7 +173,7 @@ func (w *Worker) handleRegisterJob(j *Job) error {
logoURL = md.Icon
data, err := w.getImage(md.Icon)
if err != nil {
w.ec.Append(j.Repo.ChartRepositoryID, fmt.Errorf("error getting logo image %s: %w", md.Icon, err))
w.ec.Append(j.Repo.RepositoryID, fmt.Errorf("error getting logo image %s: %w", md.Icon, err))
w.logger.Debug().Err(err).Str("url", md.Icon).Msg("get image failed")
} else {
logoImageID, err = w.is.SaveImage(w.ctx, data)
@ -186,20 +186,19 @@ func (w *Worker) handleRegisterJob(j *Job) error {
// Prepare hub package to be registered
p := &hub.Package{
Kind: hub.Chart,
Name: md.Name,
LogoURL: logoURL,
LogoImageID: logoImageID,
Description: md.Description,
Keywords: md.Keywords,
HomeURL: md.Home,
Version: md.Version,
AppVersion: md.AppVersion,
Digest: j.ChartVersion.Digest,
Deprecated: md.Deprecated,
ContentURL: u,
CreatedAt: j.ChartVersion.Created.Unix(),
ChartRepository: j.Repo,
Name: md.Name,
LogoURL: logoURL,
LogoImageID: logoImageID,
Description: md.Description,
Keywords: md.Keywords,
HomeURL: md.Home,
Version: md.Version,
AppVersion: md.AppVersion,
Digest: j.ChartVersion.Digest,
Deprecated: md.Deprecated,
ContentURL: u,
CreatedAt: j.ChartVersion.Created.Unix(),
Repository: j.Repo,
}
readme := getFile(chart, "README.md")
if readme != nil {
@ -232,7 +231,7 @@ func (w *Worker) handleRegisterJob(j *Job) error {
err = w.pm.Register(w.ctx, p)
if err != nil {
w.ec.Append(
j.Repo.ChartRepositoryID,
j.Repo.RepositoryID,
fmt.Errorf("error registering package %s version %s: %w", p.Name, p.Version, err),
)
}
@ -245,15 +244,14 @@ func (w *Worker) handleRegisterJob(j *Job) error {
func (w *Worker) handleUnregisterJob(j *Job) error {
// Unregister package
p := &hub.Package{
Kind: hub.Chart,
Name: j.ChartVersion.Name,
Version: j.ChartVersion.Version,
ChartRepository: j.Repo,
Name: j.ChartVersion.Name,
Version: j.ChartVersion.Version,
Repository: j.Repo,
}
err := w.pm.Unregister(w.ctx, p)
if err != nil {
w.ec.Append(
j.Repo.ChartRepositoryID,
j.Repo.RepositoryID,
fmt.Errorf("error unregistering package %s version %s: %w", p.Name, p.Version, err),
)
}

View File

@ -19,8 +19,8 @@ import (
)
func TestWorker(t *testing.T) {
repo1 := &hub.ChartRepository{
ChartRepositoryID: "repo1",
repo1 := &hub.Repository{
RepositoryID: "repo1",
}
logoImageURL := "http://icon.url"
@ -56,7 +56,7 @@ func TestWorker(t *testing.T) {
ww.queue <- job
close(ww.queue)
ww.hg.On("Get", job.ChartVersion.URLs[0]).Return(nil, errFake)
ww.ec.On("Append", job.Repo.ChartRepositoryID, mock.Anything).Return()
ww.ec.On("Append", job.Repo.RepositoryID, mock.Anything).Return()
// Run worker and check expectations
ww.w.Run(ww.wg, ww.queue)
@ -72,7 +72,7 @@ func TestWorker(t *testing.T) {
Body: ioutil.NopCloser(strings.NewReader("")),
StatusCode: http.StatusNotFound,
}, nil)
ww.ec.On("Append", job.Repo.ChartRepositoryID, mock.Anything).Return()
ww.ec.On("Append", job.Repo.RepositoryID, mock.Anything).Return()
// Run worker and check expectations
ww.w.Run(ww.wg, ww.queue)
@ -94,7 +94,7 @@ func TestWorker(t *testing.T) {
Body: ioutil.NopCloser(strings.NewReader("")),
StatusCode: http.StatusNotFound,
}, nil)
ww.ec.On("Append", job.Repo.ChartRepositoryID, mock.Anything).Return()
ww.ec.On("Append", job.Repo.RepositoryID, mock.Anything).Return()
ww.pm.On("Register", mock.Anything, mock.Anything).Return(nil)
// Run worker and check expectations
@ -120,7 +120,7 @@ func TestWorker(t *testing.T) {
Body: ioutil.NopCloser(strings.NewReader("")),
StatusCode: http.StatusNotFound,
}, nil)
ww.ec.On("Append", job.Repo.ChartRepositoryID, mock.Anything).Return()
ww.ec.On("Append", job.Repo.RepositoryID, mock.Anything).Return()
ww.pm.On("Register", mock.Anything, mock.Anything).Return(nil)
// Run worker and check expectations
@ -174,7 +174,7 @@ func TestWorker(t *testing.T) {
}, nil)
ww.is.On("SaveImage", mock.Anything, []byte("imageData")).Return("imageID", nil)
ww.pm.On("Register", mock.Anything, mock.Anything).Return(errFake)
ww.ec.On("Append", job.Repo.ChartRepositoryID, mock.Anything).Return()
ww.ec.On("Append", job.Repo.RepositoryID, mock.Anything).Return()
// Run worker and check expectations
ww.w.Run(ww.wg, ww.queue)
@ -255,7 +255,7 @@ func TestWorker(t *testing.T) {
ww.queue <- job
close(ww.queue)
ww.pm.On("Unregister", mock.Anything, mock.Anything).Return(errFake)
ww.ec.On("Append", job.Repo.ChartRepositoryID, mock.Anything).Return()
ww.ec.On("Append", job.Repo.RepositoryID, mock.Anything).Return()
// Run worker and check expectations
ww.w.Run(ww.wg, ww.queue)

View File

@ -9,9 +9,9 @@ import (
"time"
"github.com/artifacthub/hub/cmd/hub/handlers/apikey"
"github.com/artifacthub/hub/cmd/hub/handlers/chartrepo"
"github.com/artifacthub/hub/cmd/hub/handlers/org"
"github.com/artifacthub/hub/cmd/hub/handlers/pkg"
"github.com/artifacthub/hub/cmd/hub/handlers/repo"
"github.com/artifacthub/hub/cmd/hub/handlers/static"
"github.com/artifacthub/hub/cmd/hub/handlers/subscription"
"github.com/artifacthub/hub/cmd/hub/handlers/user"
@ -33,14 +33,14 @@ var xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
// Services is a wrapper around several internal services used by the handlers.
type Services struct {
OrganizationManager hub.OrganizationManager
UserManager hub.UserManager
PackageManager hub.PackageManager
ChartRepositoryManager hub.ChartRepositoryManager
SubscriptionManager hub.SubscriptionManager
WebhookManager hub.WebhookManager
APIKeyManager hub.APIKeyManager
ImageStore img.Store
OrganizationManager hub.OrganizationManager
UserManager hub.UserManager
RepositoryManager hub.RepositoryManager
PackageManager hub.PackageManager
SubscriptionManager hub.SubscriptionManager
WebhookManager hub.WebhookManager
APIKeyManager hub.APIKeyManager
ImageStore img.Store
}
// Metrics groups some metrics collected from a Handlers instance.
@ -57,14 +57,14 @@ type Handlers struct {
logger zerolog.Logger
Router http.Handler
Organizations *org.Handlers
Users *user.Handlers
Packages *pkg.Handlers
ChartRepositories *chartrepo.Handlers
Subscriptions *subscription.Handlers
Webhooks *webhook.Handlers
APIKeys *apikey.Handlers
Static *static.Handlers
Organizations *org.Handlers
Users *user.Handlers
Packages *pkg.Handlers
Repositories *repo.Handlers
Subscriptions *subscription.Handlers
Webhooks *webhook.Handlers
APIKeys *apikey.Handlers
Static *static.Handlers
}
// Setup creates a new Handlers instance.
@ -75,14 +75,14 @@ func Setup(cfg *viper.Viper, svc *Services) *Handlers {
metrics: setupMetrics(),
logger: log.With().Str("handlers", "root").Logger(),
Organizations: org.NewHandlers(svc.OrganizationManager, cfg),
Users: user.NewHandlers(svc.UserManager, cfg),
Packages: pkg.NewHandlers(svc.PackageManager, cfg),
Subscriptions: subscription.NewHandlers(svc.SubscriptionManager),
ChartRepositories: chartrepo.NewHandlers(svc.ChartRepositoryManager),
Webhooks: webhook.NewHandlers(svc.WebhookManager),
APIKeys: apikey.NewHandlers(svc.APIKeyManager),
Static: static.NewHandlers(cfg, svc.ImageStore),
Organizations: org.NewHandlers(svc.OrganizationManager, cfg),
Users: user.NewHandlers(svc.UserManager, cfg),
Repositories: repo.NewHandlers(svc.RepositoryManager),
Packages: pkg.NewHandlers(svc.PackageManager, cfg),
Subscriptions: subscription.NewHandlers(svc.SubscriptionManager),
Webhooks: webhook.NewHandlers(svc.WebhookManager),
APIKeys: apikey.NewHandlers(svc.APIKeyManager),
Static: static.NewHandlers(cfg, svc.ImageStore),
}
h.setupRouter()
return h
@ -168,25 +168,25 @@ func (h *Handlers) setupRouter() {
})
})
// Chart repositories
r.Route("/chart-repositories", func(r chi.Router) {
// Repositories
r.Route("/repositories", func(r chi.Router) {
r.Use(h.Users.RequireLogin)
r.Route("/user", func(r chi.Router) {
r.Get("/", h.ChartRepositories.GetOwnedByUser)
r.Post("/", h.ChartRepositories.Add)
r.Get("/", h.Repositories.GetOwnedByUser)
r.Post("/", h.Repositories.Add)
r.Route("/{repoName}", func(r chi.Router) {
r.Put("/transfer", h.ChartRepositories.Transfer)
r.Put("/", h.ChartRepositories.Update)
r.Delete("/", h.ChartRepositories.Delete)
r.Put("/transfer", h.Repositories.Transfer)
r.Put("/", h.Repositories.Update)
r.Delete("/", h.Repositories.Delete)
})
})
r.Route("/org/{orgName}", func(r chi.Router) {
r.Get("/", h.ChartRepositories.GetOwnedByOrg)
r.Post("/", h.ChartRepositories.Add)
r.Get("/", h.Repositories.GetOwnedByOrg)
r.Post("/", h.Repositories.Add)
r.Route("/{repoName}", func(r chi.Router) {
r.Put("/transfer", h.ChartRepositories.Transfer)
r.Put("/", h.ChartRepositories.Update)
r.Delete("/", h.ChartRepositories.Delete)
r.Put("/transfer", h.Repositories.Transfer)
r.Put("/", h.Repositories.Update)
r.Delete("/", h.Repositories.Delete)
})
})
})
@ -197,12 +197,7 @@ func (h *Handlers) setupRouter() {
r.Get("/stats", h.Packages.GetStats)
r.Get("/search", h.Packages.Search)
r.With(h.Users.RequireLogin).Get("/starred", h.Packages.GetStarredByUser)
r.Route("/chart/{repoName}/{packageName}", func(r chi.Router) {
r.Get("/feed/rss", h.Packages.RssFeed)
r.Get("/{version}", h.Packages.Get)
r.Get("/", h.Packages.Get)
})
r.Route("/{^falco$|^opa$}/{packageName}", func(r chi.Router) {
r.Route("/{^helm$|^falco$|^opa$|^olm$}/{repoName}/{packageName}", func(r chi.Router) {
r.Get("/feed/rss", h.Packages.RssFeed)
r.Get("/{version}", h.Packages.Get)
r.Get("/", h.Packages.Get)
@ -260,7 +255,7 @@ func (h *Handlers) setupRouter() {
// Availability checks
r.Route("/check-availability", func(r chi.Router) {
r.Head("/{resourceKind:^chartRepositoryName$|^chartRepositoryURL$}", h.ChartRepositories.CheckAvailability)
r.Head("/{resourceKind:^repositoryName$|^repositoryURL$}", h.Repositories.CheckAvailability)
r.Head("/{resourceKind:^organizationName$}", h.Organizations.CheckAvailability)
r.Head("/{resourceKind:^userAlias$}", h.Users.CheckAvailability)
})
@ -283,11 +278,7 @@ func (h *Handlers) setupRouter() {
// Index special entry points
r.Route("/packages", func(r chi.Router) {
r.Route("/chart/{repoName}/{packageName}", func(r chi.Router) {
r.With(h.Packages.InjectIndexMeta).Get("/{version}", h.Static.ServeIndex)
r.With(h.Packages.InjectIndexMeta).Get("/", h.Static.ServeIndex)
})
r.Route("/{^falco$|^opa$}/{packageName}", func(r chi.Router) {
r.Route("/{^helm$|^falco$|^opa$|^olm$}/{repoName}/{packageName}", func(r chi.Router) {
r.With(h.Packages.InjectIndexMeta).Get("/{version}", h.Static.ServeIndex)
r.With(h.Packages.InjectIndexMeta).Get("/", h.Static.ServeIndex)
})

View File

@ -42,9 +42,9 @@ func (h *Handlers) Get(w http.ResponseWriter, r *http.Request) {
PackageName: chi.URLParam(r, "packageName"),
Version: chi.URLParam(r, "version"),
}
chartRepositoryName := chi.URLParam(r, "repoName")
if chartRepositoryName != "" {
input.ChartRepositoryName = chartRepositoryName
repoName := chi.URLParam(r, "repoName")
if repoName != "" {
input.RepositoryName = repoName
}
dataJSON, err := h.pkgManager.GetJSON(r.Context(), input)
if err != nil {
@ -113,9 +113,9 @@ func (h *Handlers) InjectIndexMeta(next http.Handler) http.Handler {
PackageName: chi.URLParam(r, "packageName"),
Version: chi.URLParam(r, "version"),
}
chartRepositoryName := chi.URLParam(r, "repoName")
if chartRepositoryName != "" {
input.ChartRepositoryName = chartRepositoryName
repoName := chi.URLParam(r, "repoName")
if repoName != "" {
input.RepositoryName = repoName
}
p, err := h.pkgManager.Get(r.Context(), input)
if err != nil {
@ -123,15 +123,11 @@ func (h *Handlers) InjectIndexMeta(next http.Handler) http.Handler {
helpers.RenderErrorJSON(w, err)
return
}
publisher := p.OrganizationName
publisher := p.Repository.OrganizationName
if publisher == "" {
publisher = p.UserAlias
publisher = p.Repository.UserAlias
}
repo := ""
if p.ChartRepository != nil {
repo = "/" + p.ChartRepository.Name
}
title := fmt.Sprintf("%s %s · %s%s", p.NormalizedName, p.Version, publisher, repo)
title := fmt.Sprintf("%s %s · %s/%s", p.NormalizedName, p.Version, publisher, p.Repository.Name)
description := p.Description
// Inject index metadata in context and call next handler
@ -147,9 +143,9 @@ func (h *Handlers) RssFeed(w http.ResponseWriter, r *http.Request) {
input := &hub.GetPackageInput{
PackageName: chi.URLParam(r, "packageName"),
}
chartRepositoryName := chi.URLParam(r, "repoName")
if chartRepositoryName != "" {
input.ChartRepositoryName = chartRepositoryName
repoName := chi.URLParam(r, "repoName")
if repoName != "" {
input.RepositoryName = repoName
}
p, err := h.pkgManager.Get(r.Context(), input)
if err != nil {
@ -160,9 +156,9 @@ func (h *Handlers) RssFeed(w http.ResponseWriter, r *http.Request) {
// Build RSS feed
baseURL := h.cfg.GetString("server.baseURL")
publisher := p.OrganizationName
publisher := p.Repository.OrganizationName
if publisher == "" {
publisher = p.UserAlias
publisher = p.Repository.UserAlias
}
feed := &feeds.Feed{
Title: fmt.Sprintf("%s/%s (Artifact Hub)", publisher, p.NormalizedName),
@ -264,13 +260,13 @@ func buildSearchInput(qs url.Values) (*hub.SearchPackageInput, error) {
}
// Kinds
kinds := make([]hub.PackageKind, 0, len(qs["kind"]))
kinds := make([]hub.RepositoryKind, 0, len(qs["kind"]))
for _, kindStr := range qs["kind"] {
kind, err := strconv.Atoi(kindStr)
if err != nil {
return nil, fmt.Errorf("invalid kind: %s", kindStr)
}
kinds = append(kinds, hub.PackageKind(kind))
kinds = append(kinds, hub.RepositoryKind(kind))
}
// Include deprecated packages
@ -284,29 +280,25 @@ func buildSearchInput(qs url.Values) (*hub.SearchPackageInput, error) {
}
return &hub.SearchPackageInput{
Limit: limit,
Offset: offset,
Facets: facets,
Text: qs.Get("text"),
PackageKinds: kinds,
Users: qs["user"],
Orgs: qs["org"],
ChartRepositories: qs["repo"],
Deprecated: deprecated,
Limit: limit,
Offset: offset,
Facets: facets,
Text: qs.Get("text"),
Users: qs["user"],
Orgs: qs["org"],
Repositories: qs["repo"],
RepositoryKinds: kinds,
Deprecated: deprecated,
}, nil
}
// BuildPackageURL builds the url of a given package.
func BuildPackageURL(baseURL string, p *hub.Package, version string) string {
var pkgPath string
switch p.Kind {
case hub.Chart:
pkgPath = fmt.Sprintf("/packages/chart/%s/%s", p.ChartRepository.Name, p.NormalizedName)
case hub.Falco:
pkgPath = fmt.Sprintf("/packages/falco/%s", p.NormalizedName)
case hub.OPA:
pkgPath = fmt.Sprintf("/packages/opa/%s", p.NormalizedName)
}
pkgPath := fmt.Sprintf("/packages/%s/%s/%s",
hub.GetKindName(p.Repository.Kind),
p.Repository.Name,
p.NormalizedName,
)
if version != "" {
pkgPath += "/" + version
}

View File

@ -308,12 +308,12 @@ func TestInjectIndexMeta(t *testing.T) {
}{
{
&hub.Package{
NormalizedName: "pkg1",
Version: "1.0.0",
Description: "description",
OrganizationName: "org1",
ChartRepository: &hub.ChartRepository{
Name: "repo1",
NormalizedName: "pkg1",
Version: "1.0.0",
Description: "description",
Repository: &hub.Repository{
Name: "repo1",
OrganizationName: "org1",
},
},
"pkg1 1.0.0 · org1/repo1",
@ -324,25 +324,15 @@ func TestInjectIndexMeta(t *testing.T) {
&hub.Package{
NormalizedName: "pkg1",
Version: "1.0.0",
UserAlias: "user1",
ChartRepository: &hub.ChartRepository{
Name: "repo1",
Repository: &hub.Repository{
Name: "repo1",
UserAlias: "user1",
},
},
"pkg1 1.0.0 · user1/repo1",
"",
http.StatusOK,
},
{
&hub.Package{
NormalizedName: "pkg1",
Version: "1.0.0",
UserAlias: "user1",
},
"pkg1 1.0.0 · user1",
"",
http.StatusOK,
},
}
for _, tc := range testCases {
tc := tc
@ -409,13 +399,12 @@ func TestRssFeed(t *testing.T) {
}{
{
&hub.Package{
PackageID: "0001",
NormalizedName: "pkg1",
Description: "description",
Version: "1.0.0",
LogoImageID: "0001",
CreatedAt: 1592299234,
OrganizationName: "org1",
PackageID: "0001",
NormalizedName: "pkg1",
Description: "description",
Version: "1.0.0",
LogoImageID: "0001",
CreatedAt: 1592299234,
AvailableVersions: []*hub.Version{
{
Version: "1.0.0",
@ -432,8 +421,9 @@ func TestRssFeed(t *testing.T) {
Email: "email1",
},
},
ChartRepository: &hub.ChartRepository{
Name: "repo1",
Repository: &hub.Repository{
Name: "repo1",
OrganizationName: "org1",
},
},
[]byte(`<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
@ -449,14 +439,14 @@ func TestRssFeed(t *testing.T) {
</image>
<item>
<title>1.0.0</title>
<link>baseURL/packages/chart/repo1/pkg1/1.0.0</link>
<link>baseURL/packages/helm/repo1/pkg1/1.0.0</link>
<description>pkg1 1.0.0</description>
<guid>0001#1.0.0</guid>
<pubDate>Tue, 16 Jun 2020 09:20:34 +0000</pubDate>
</item>
<item>
<title>0.0.9</title>
<link>baseURL/packages/chart/repo1/pkg1/0.0.9</link>
<link>baseURL/packages/helm/repo1/pkg1/0.0.9</link>
<description>pkg1 0.0.9</description>
<guid>0001#0.0.9</guid>
<pubDate>Tue, 16 Jun 2020 09:20:33 +0000</pubDate>
@ -651,41 +641,58 @@ func TestBuildPackageURL(t *testing.T) {
}{
{
&hub.Package{
Kind: hub.Chart,
NormalizedName: "pkg1",
ChartRepository: &hub.ChartRepository{
Repository: &hub.Repository{
Kind: hub.Helm,
Name: "repo1",
},
},
"1.0.0",
baseURL + "/packages/chart/repo1/pkg1/1.0.0",
baseURL + "/packages/helm/repo1/pkg1/1.0.0",
},
{
&hub.Package{
Kind: hub.Chart,
NormalizedName: "pkg1",
ChartRepository: &hub.ChartRepository{
Repository: &hub.Repository{
Kind: hub.Helm,
Name: "repo1",
},
},
"",
baseURL + "/packages/chart/repo1/pkg1",
baseURL + "/packages/helm/repo1/pkg1",
},
{
&hub.Package{
Kind: hub.Falco,
NormalizedName: "pkg1",
Repository: &hub.Repository{
Kind: hub.Falco,
Name: "repo1",
},
},
"",
baseURL + "/packages/falco/pkg1",
baseURL + "/packages/falco/repo1/pkg1",
},
{
&hub.Package{
Kind: hub.OPA,
NormalizedName: "pkg1",
Repository: &hub.Repository{
Kind: hub.OPA,
Name: "repo1",
},
},
"",
baseURL + "/packages/opa/pkg1",
baseURL + "/packages/opa/repo1/pkg1",
},
{
&hub.Package{
NormalizedName: "pkg1",
Repository: &hub.Repository{
Kind: hub.OLM,
Name: "repo1",
},
},
"2.0.0",
baseURL + "/packages/olm/repo1/pkg1/2.0.0",
},
}
for _, tc := range testCases {

View File

@ -1,4 +1,4 @@
package chartrepo
package repo
import (
"encoding/json"
@ -11,32 +11,31 @@ import (
"github.com/rs/zerolog/log"
)
// Handlers represents a group of http handlers in charge of handling chart
// Handlers represents a group of http handlers in charge of handling
// repositories operations.
type Handlers struct {
chartRepoManager hub.ChartRepositoryManager
logger zerolog.Logger
repoManager hub.RepositoryManager
logger zerolog.Logger
}
// NewHandlers creates a new Handlers instance.
func NewHandlers(chartRepoManager hub.ChartRepositoryManager) *Handlers {
func NewHandlers(repoManager hub.RepositoryManager) *Handlers {
return &Handlers{
chartRepoManager: chartRepoManager,
logger: log.With().Str("handlers", "chartrepo").Logger(),
repoManager: repoManager,
logger: log.With().Str("handlers", "repo").Logger(),
}
}
// Add is an http handler that adds the provided chart repository to the
// database.
// Add is an http handler that adds the provided repository to the database.
func (h *Handlers) Add(w http.ResponseWriter, r *http.Request) {
orgName := chi.URLParam(r, "orgName")
repo := &hub.ChartRepository{}
repo := &hub.Repository{}
if err := json.NewDecoder(r.Body).Decode(&repo); err != nil {
h.logger.Error().Err(err).Str("method", "Add").Msg(hub.ErrInvalidInput.Error())
helpers.RenderErrorJSON(w, hub.ErrInvalidInput)
return
}
if err := h.chartRepoManager.Add(r.Context(), orgName, repo); err != nil {
if err := h.repoManager.Add(r.Context(), orgName, repo); err != nil {
h.logger.Error().Err(err).Str("method", "Add").Send()
helpers.RenderErrorJSON(w, err)
return
@ -50,7 +49,7 @@ func (h *Handlers) CheckAvailability(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", helpers.BuildCacheControlHeader(0))
resourceKind := chi.URLParam(r, "resourceKind")
value := r.FormValue("v")
available, err := h.chartRepoManager.CheckAvailability(r.Context(), resourceKind, value)
available, err := h.repoManager.CheckAvailability(r.Context(), resourceKind, value)
if err != nil {
h.logger.Error().Err(err).Str("method", "CheckAvailability").Send()
helpers.RenderErrorJSON(w, err)
@ -63,11 +62,11 @@ func (h *Handlers) CheckAvailability(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}
// Delete is an http handler that deletes the provided chart repository from
// the database.
// Delete is an http handler that deletes the provided repository from the
// database.
func (h *Handlers) Delete(w http.ResponseWriter, r *http.Request) {
repoName := chi.URLParam(r, "repoName")
if err := h.chartRepoManager.Delete(r.Context(), repoName); err != nil {
if err := h.repoManager.Delete(r.Context(), repoName); err != nil {
h.logger.Error().Err(err).Str("method", "Delete").Send()
helpers.RenderErrorJSON(w, err)
return
@ -75,12 +74,12 @@ func (h *Handlers) Delete(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}
// GetOwnedByOrg is an http handler that returns the chart repositories owned
// by the organization provided. The user doing the request must belong to the
// GetOwnedByOrg is an http handler that returns the repositories owned by the
// organization provided. The user doing the request must belong to the
// organization.
func (h *Handlers) GetOwnedByOrg(w http.ResponseWriter, r *http.Request) {
orgName := chi.URLParam(r, "orgName")
dataJSON, err := h.chartRepoManager.GetOwnedByOrgJSON(r.Context(), orgName)
dataJSON, err := h.repoManager.GetOwnedByOrgJSON(r.Context(), orgName)
if err != nil {
h.logger.Error().Err(err).Str("method", "GetOwnedByOrg").Send()
helpers.RenderErrorJSON(w, err)
@ -89,10 +88,10 @@ func (h *Handlers) GetOwnedByOrg(w http.ResponseWriter, r *http.Request) {
helpers.RenderJSON(w, dataJSON, 0, http.StatusOK)
}
// GetOwnedByUser is an http handler that returns the chart repositories owned
// by the user doing the request.
// GetOwnedByUser is an http handler that returns the repositories owned by the
// user doing the request.
func (h *Handlers) GetOwnedByUser(w http.ResponseWriter, r *http.Request) {
dataJSON, err := h.chartRepoManager.GetOwnedByUserJSON(r.Context())
dataJSON, err := h.repoManager.GetOwnedByUserJSON(r.Context())
if err != nil {
h.logger.Error().Err(err).Str("method", "GetOwnedByUser").Send()
helpers.RenderErrorJSON(w, err)
@ -101,12 +100,12 @@ func (h *Handlers) GetOwnedByUser(w http.ResponseWriter, r *http.Request) {
helpers.RenderJSON(w, dataJSON, 0, http.StatusOK)
}
// Transfer is an http handler that transfers the provided chart repository to
// a different owner.
// Transfer is an http handler that transfers the provided repository to a
// different owner.
func (h *Handlers) Transfer(w http.ResponseWriter, r *http.Request) {
repoName := chi.URLParam(r, "repoName")
orgName := r.FormValue("org")
if err := h.chartRepoManager.Transfer(r.Context(), repoName, orgName); err != nil {
if err := h.repoManager.Transfer(r.Context(), repoName, orgName); err != nil {
h.logger.Error().Err(err).Str("method", "Transfer").Send()
helpers.RenderErrorJSON(w, err)
return
@ -114,17 +113,17 @@ func (h *Handlers) Transfer(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}
// Update is an http handler that updates the provided chart repository in the
// Update is an http handler that updates the provided repository in the
// database.
func (h *Handlers) Update(w http.ResponseWriter, r *http.Request) {
repo := &hub.ChartRepository{}
repo := &hub.Repository{}
if err := json.NewDecoder(r.Body).Decode(&repo); err != nil {
h.logger.Error().Err(err).Str("method", "Update").Msg("invalid chart repository")
h.logger.Error().Err(err).Str("method", "Update").Msg("invalid repository")
helpers.RenderErrorJSON(w, hub.ErrInvalidInput)
return
}
repo.Name = chi.URLParam(r, "repoName")
if err := h.chartRepoManager.Update(r.Context(), repo); err != nil {
if err := h.repoManager.Update(r.Context(), repo); err != nil {
h.logger.Error().Err(err).Str("method", "Update").Send()
helpers.RenderErrorJSON(w, err)
return

View File

@ -1,4 +1,4 @@
package chartrepo
package repo
import (
"context"
@ -12,8 +12,8 @@ import (
"testing"
"github.com/artifacthub/hub/cmd/hub/handlers/helpers"
"github.com/artifacthub/hub/internal/chartrepo"
"github.com/artifacthub/hub/internal/hub"
"github.com/artifacthub/hub/internal/repo"
"github.com/artifacthub/hub/internal/tests"
"github.com/go-chi/chi"
"github.com/rs/zerolog"
@ -41,7 +41,7 @@ func TestAdd(t *testing.T) {
rmErr error
}{
{
"no chart repository provided",
"no repository provided",
"",
nil,
},
@ -78,7 +78,7 @@ func TestAdd(t *testing.T) {
}
})
t.Run("valid chart repository provided", func(t *testing.T) {
t.Run("valid repository provided", func(t *testing.T) {
repoJSON := `
{
"name": "repo1",
@ -86,7 +86,7 @@ func TestAdd(t *testing.T) {
"url": "https://repo1.url"
}
`
repo := &hub.ChartRepository{}
repo := &hub.Repository{}
_ = json.Unmarshal([]byte(repoJSON), &repo)
testCases := []struct {
@ -95,17 +95,17 @@ func TestAdd(t *testing.T) {
expectedStatusCode int
}{
{
"add chart repository succeeded",
"add repository succeeded",
nil,
http.StatusCreated,
},
{
"error adding chart repository (insufficient privilege)",
"error adding repository (insufficient privilege)",
hub.ErrInsufficientPrivilege,
http.StatusForbidden,
},
{
"error adding chart repository (db error)",
"error adding repository (db error)",
tests.ErrFakeDatabaseFailure,
http.StatusInternalServerError,
},
@ -162,11 +162,11 @@ func TestCheckAvailability(t *testing.T) {
available bool
}{
{
"chartRepositoryName",
"repositoryName",
true,
},
{
"chartRepositoryURL",
"repositoryURL",
false,
},
}
@ -208,13 +208,13 @@ func TestCheckAvailability(t *testing.T) {
rctx := &chi.Context{
URLParams: chi.RouteParams{
Keys: []string{"resourceKind"},
Values: []string{"chartRepositoryName"},
Values: []string{"repositoryName"},
},
}
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
hw := newHandlersWrapper()
hw.rm.On("CheckAvailability", r.Context(), "chartRepositoryName", "value").
hw.rm.On("CheckAvailability", r.Context(), "repositoryName", "value").
Return(false, tests.ErrFakeDatabaseFailure)
hw.h.CheckAvailability(w, r)
resp := w.Result()
@ -234,7 +234,7 @@ func TestDelete(t *testing.T) {
},
}
t.Run("delete chart repository succeeded", func(t *testing.T) {
t.Run("delete repository succeeded", func(t *testing.T) {
w := httptest.NewRecorder()
r, _ := http.NewRequest("DELETE", "/", nil)
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
@ -250,7 +250,7 @@ func TestDelete(t *testing.T) {
hw.rm.AssertExpectations(t)
})
t.Run("error deleting chart repository", func(t *testing.T) {
t.Run("error deleting repository", func(t *testing.T) {
testCases := []struct {
rmErr error
expectedStatusCode int
@ -297,7 +297,7 @@ func TestGetOwnedByOrg(t *testing.T) {
},
}
t.Run("get chart repositories owned by organization succeeded", func(t *testing.T) {
t.Run("get repositories owned by organization succeeded", func(t *testing.T) {
w := httptest.NewRecorder()
r, _ := http.NewRequest("GET", "/", nil)
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
@ -318,7 +318,7 @@ func TestGetOwnedByOrg(t *testing.T) {
hw.rm.AssertExpectations(t)
})
t.Run("error getting chart repositories owned by organization", func(t *testing.T) {
t.Run("error getting repositories owned by organization", func(t *testing.T) {
testCases := []struct {
rmErr error
expectedStatusCode int
@ -354,7 +354,7 @@ func TestGetOwnedByOrg(t *testing.T) {
}
func TestGetOwnedByUser(t *testing.T) {
t.Run("get chart repositories owned by user succeeded", func(t *testing.T) {
t.Run("get repositories owned by user succeeded", func(t *testing.T) {
w := httptest.NewRecorder()
r, _ := http.NewRequest("GET", "/", nil)
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
@ -374,7 +374,7 @@ func TestGetOwnedByUser(t *testing.T) {
hw.rm.AssertExpectations(t)
})
t.Run("error getting chart repositories owned by user", func(t *testing.T) {
t.Run("error getting repositories owned by user", func(t *testing.T) {
w := httptest.NewRecorder()
r, _ := http.NewRequest("GET", "/", nil)
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
@ -391,7 +391,7 @@ func TestGetOwnedByUser(t *testing.T) {
}
func TestTransfer(t *testing.T) {
t.Run("invalid input - missing chart repo name", func(t *testing.T) {
t.Run("invalid input - missing repo name", func(t *testing.T) {
w := httptest.NewRecorder()
r, _ := http.NewRequest("PUT", "/", nil)
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
@ -413,17 +413,17 @@ func TestTransfer(t *testing.T) {
expectedStatusCode int
}{
{
"chart repository transferred succeeded",
"repository transferred succeeded",
nil,
http.StatusNoContent,
},
{
"error transferring chart repository (insufficient privilege)",
"error transferring repository (insufficient privilege)",
hub.ErrInsufficientPrivilege,
http.StatusForbidden,
},
{
"error transferring chart repository (db error)",
"error transferring repository (db error)",
tests.ErrFakeDatabaseFailure,
http.StatusInternalServerError,
},
@ -463,7 +463,7 @@ func TestUpdate(t *testing.T) {
rmErr error
}{
{
"no chart repository provided",
"no repository provided",
"",
nil,
},
@ -499,14 +499,14 @@ func TestUpdate(t *testing.T) {
}
})
t.Run("valid chart repository provided", func(t *testing.T) {
t.Run("valid repository provided", func(t *testing.T) {
repoJSON := `
{
"display_name": "Repository 1 updated",
"url": "https://repo1.url/updated"
}
`
repo := &hub.ChartRepository{}
repo := &hub.Repository{}
_ = json.Unmarshal([]byte(repoJSON), &repo)
testCases := []struct {
@ -515,17 +515,17 @@ func TestUpdate(t *testing.T) {
expectedStatusCode int
}{
{
"chart repository update succeeded",
"repository update succeeded",
nil,
http.StatusNoContent,
},
{
"error updating chart repository (insufficient privilege)",
"error updating repository (insufficient privilege)",
hub.ErrInsufficientPrivilege,
http.StatusForbidden,
},
{
"error updating chart repository (db error)",
"error updating repository (db error)",
tests.ErrFakeDatabaseFailure,
http.StatusInternalServerError,
},
@ -551,12 +551,12 @@ func TestUpdate(t *testing.T) {
}
type handlersWrapper struct {
rm *chartrepo.ManagerMock
rm *repo.ManagerMock
h *Handlers
}
func newHandlersWrapper() *handlersWrapper {
rm := &chartrepo.ManagerMock{}
rm := &repo.ManagerMock{}
return &handlersWrapper{
rm: rm,

View File

@ -176,10 +176,13 @@ var webhookTestTemplateData = &hub.NotificationTemplateData{
"kind": "package.new-release",
},
Package: map[string]interface{}{
"kind": "helm-chart",
"name": "sample-package",
"version": "1.0.0",
"publisher": "artifacthub",
"url": "https://artifacthub.io/packages/chart/artifacthub/sample-package",
"name": "sample-package",
"version": "1.0.0",
"url": "https://artifacthub.io/packages/helm/artifacthub/sample-package/1.0.0",
"repository": map[string]interface{}{
"kind": "helm",
"name": "repo1",
"publisher": "org1",
},
},
}

View File

@ -506,11 +506,14 @@ func TestTriggerTest(t *testing.T) {
"datacontenttype" : "application/json",
"data" : {
"package": {
"kind": "helm-chart",
"name": "sample-package",
"version": "1.0.0",
"publisher": "artifacthub",
"url": "https://artifacthub.io/packages/chart/artifacthub/sample-package"
"url": "https://artifacthub.io/packages/helm/artifacthub/sample-package/1.0.0",
"repository": {
"kind": "helm",
"name": "repo1",
"publisher": "org1"
}
}
}
}

View File

@ -11,7 +11,6 @@ import (
"github.com/artifacthub/hub/cmd/hub/handlers"
"github.com/artifacthub/hub/internal/apikey"
"github.com/artifacthub/hub/internal/chartrepo"
"github.com/artifacthub/hub/internal/email"
"github.com/artifacthub/hub/internal/event"
"github.com/artifacthub/hub/internal/hub"
@ -19,6 +18,7 @@ import (
"github.com/artifacthub/hub/internal/notification"
"github.com/artifacthub/hub/internal/org"
"github.com/artifacthub/hub/internal/pkg"
"github.com/artifacthub/hub/internal/repo"
"github.com/artifacthub/hub/internal/subscription"
"github.com/artifacthub/hub/internal/user"
"github.com/artifacthub/hub/internal/util"
@ -50,14 +50,14 @@ func main() {
// Setup and launch http server
hSvc := &handlers.Services{
OrganizationManager: org.NewManager(db, es),
UserManager: user.NewManager(db, es),
PackageManager: pkg.NewManager(db),
SubscriptionManager: subscription.NewManager(db),
ChartRepositoryManager: chartrepo.NewManager(db),
WebhookManager: webhook.NewManager(db),
APIKeyManager: apikey.NewManager(db),
ImageStore: pg.NewImageStore(db),
OrganizationManager: org.NewManager(db, es),
UserManager: user.NewManager(db, es),
RepositoryManager: repo.NewManager(db),
PackageManager: pkg.NewManager(db),
SubscriptionManager: subscription.NewManager(db),
WebhookManager: webhook.NewManager(db),
APIKeyManager: apikey.NewManager(db),
ImageStore: pg.NewImageStore(db),
}
addr := cfg.GetString("server.addr")
srv := &http.Server{

View File

@ -21,7 +21,7 @@ import (
)
var basePath = flag.String("base-path", ".", "Path containing SecurityHub yaml files to process")
var orgID = flag.String("org-id", "", "ID of the organization that will own the packages added")
var repoID = flag.String("repo-id", "", "ID of the repository that will own the packages added")
func main() {
flag.Parse()
@ -62,7 +62,7 @@ func main() {
if !strings.HasSuffix(info.Name(), "yaml") {
return nil
}
return r.registerPackage(*orgID, *basePath, path)
return r.registerPackage(*repoID, *basePath, path)
})
if err != nil {
log.Fatal().Err(err).Msg("Error processing SecurityHub yaml files")
@ -122,20 +122,21 @@ func (r *SecurityHubRegistrar) registerPackage(orgID, basePath, pkgPath string)
// Build package to register
p := &hub.Package{
Name: e.Name,
LogoURL: logoURL,
LogoImageID: logoImageID,
Description: e.ShortDescription,
Keywords: e.Keywords,
Version: e.Version,
Readme: e.Description,
OrganizationID: orgID,
Name: e.Name,
LogoURL: logoURL,
LogoImageID: logoImageID,
Description: e.ShortDescription,
Keywords: e.Keywords,
Version: e.Version,
Readme: e.Description,
Repository: &hub.Repository{
RepositoryID: *repoID,
},
}
switch e.Kind {
case "FalcoRules":
yamlFile := strings.TrimPrefix(pkgPath, basePath)
sourceURL := fmt.Sprintf("https://github.com/falcosecurity/cloud-native-security-hub/blob/master/resources%s", yamlFile)
p.Kind = hub.Falco
p.Links = []*hub.Link{
{
Name: "source",
@ -143,17 +144,6 @@ func (r *SecurityHubRegistrar) registerPackage(orgID, basePath, pkgPath string)
},
}
p.Data = map[string]interface{}{"rules": e.Rules}
case "OpenPolicyAgentPolicies":
yamlFile := strings.TrimPrefix(pkgPath, basePath)
sourceURL := fmt.Sprintf("https://github.com/falcosecurity/cloud-native-security-hub/blob/master/resources%s", yamlFile)
p.Kind = hub.OPA
p.Links = []*hub.Link{
{
Name: "source",
URL: sourceURL,
},
}
p.Data = map[string]interface{}{"policies": e.Policies}
}
return r.pkgManager.Register(r.ctx, p)

View File

@ -4,6 +4,15 @@
{{ template "api_keys/get_user_api_keys.sql" }}
{{ template "api_keys/update_api_key.sql" }}
{{ template "events/get_pending_event.sql" }}
{{ template "images/get_image.sql" }}
{{ template "images/register_image.sql" }}
{{ template "notifications/add_notification.sql" }}
{{ template "notifications/get_pending_notification.sql" }}
{{ template "notifications/update_notification_status.sql" }}
{{ template "organizations/add_organization_member.sql" }}
{{ template "organizations/add_organization.sql" }}
{{ template "organizations/confirm_organization_membership.sql" }}
@ -14,13 +23,6 @@
{{ template "organizations/update_organization.sql" }}
{{ template "organizations/user_belongs_to_organization.sql" }}
{{ template "users/get_user_profile.sql" }}
{{ template "users/register_session.sql" }}
{{ template "users/register_user.sql" }}
{{ template "users/update_user_password.sql" }}
{{ template "users/update_user_profile.sql" }}
{{ template "users/verify_email.sql" }}
{{ template "packages/generate_package_tsdoc.sql" }}
{{ template "packages/get_package.sql" }}
{{ template "packages/get_package_summary.sql" }}
@ -35,18 +37,15 @@
{{ template "packages/toggle_star.sql" }}
{{ template "packages/unregister_package.sql" }}
{{ template "chart_repositories/add_chart_repository.sql" }}
{{ template "chart_repositories/delete_chart_repository.sql" }}
{{ template "chart_repositories/get_chart_repositories.sql" }}
{{ template "chart_repositories/get_chart_repository_by_name.sql" }}
{{ template "chart_repositories/get_chart_repository_packages_digest.sql" }}
{{ template "chart_repositories/get_org_chart_repositories.sql" }}
{{ template "chart_repositories/get_user_chart_repositories.sql" }}
{{ template "chart_repositories/transfer_chart_repository.sql" }}
{{ template "chart_repositories/update_chart_repository.sql" }}
{{ template "images/get_image.sql" }}
{{ template "images/register_image.sql" }}
{{ template "repositories/add_repository.sql" }}
{{ template "repositories/delete_repository.sql" }}
{{ template "repositories/get_repositories_by_kind.sql" }}
{{ template "repositories/get_repository_by_name.sql" }}
{{ template "repositories/get_repository_packages_digest.sql" }}
{{ template "repositories/get_org_repositories.sql" }}
{{ template "repositories/get_user_repositories.sql" }}
{{ template "repositories/transfer_repository.sql" }}
{{ template "repositories/update_repository.sql" }}
{{ template "subscriptions/add_subscription.sql" }}
{{ template "subscriptions/delete_subscription.sql" }}
@ -54,11 +53,12 @@
{{ template "subscriptions/get_subscriptors.sql" }}
{{ template "subscriptions/get_user_subscriptions.sql" }}
{{ template "events/get_pending_event.sql" }}
{{ template "notifications/add_notification.sql" }}
{{ template "notifications/get_pending_notification.sql" }}
{{ template "notifications/update_notification_status.sql" }}
{{ template "users/get_user_profile.sql" }}
{{ template "users/register_session.sql" }}
{{ template "users/register_user.sql" }}
{{ template "users/update_user_password.sql" }}
{{ template "users/update_user_profile.sql" }}
{{ template "users/verify_email.sql" }}
{{ template "webhooks/add_webhook.sql" }}
{{ template "webhooks/delete_webhook.sql" }}

View File

@ -1,12 +0,0 @@
-- get_chart_repositories returns all available chart repositories as a json
-- array.
create or replace function get_chart_repositories()
returns setof json as $$
select coalesce(json_agg(json_build_object(
'chart_repository_id', chart_repository_id,
'name', name,
'display_name', display_name,
'url', url
)), '[]')
from chart_repository;
$$ language sql;

View File

@ -1,13 +0,0 @@
-- get_chart_repository_by_name returns the repository identified by the name
-- provided as a json object.
create or replace function get_chart_repository_by_name(p_name text)
returns setof json as $$
select json_build_object(
'chart_repository_id', chart_repository_id,
'name', name,
'display_name', display_name,
'url', url
)
from chart_repository
where name = p_name;
$$ language sql;

View File

@ -1,9 +0,0 @@
-- get_chart_repository_packages_digest returns the digest of all packages that
-- belong to the chart repository identified by the id provided.
create or replace function get_chart_repository_packages_digest(p_chart_repository_id uuid)
returns setof json as $$
select coalesce(json_object_agg(format('%s@%s', p.name, s.version), s.digest), '{}')
from package p
join snapshot s using (package_id)
where p.chart_repository_id = p_chart_repository_id;
$$ language sql;

View File

@ -1,20 +0,0 @@
-- get_org_chart_repositories returns all available chart repositories that
-- belong to the provided organization as a json array. The user provided must
-- belong to the organization used.
create or replace function get_org_chart_repositories(p_user_id uuid, p_org_name text)
returns setof json as $$
select coalesce(json_agg(json_build_object(
'chart_repository_id', cr.chart_repository_id,
'name', cr.name,
'display_name', cr.display_name,
'url', cr.url,
'last_tracking_ts', floor(extract(epoch from cr.last_tracking_ts)),
'last_tracking_errors', cr.last_tracking_errors
)), '[]')
from chart_repository cr
join organization o using (organization_id)
join user__organization uo using (organization_id)
where o.name = p_org_name
and uo.user_id = p_user_id
and uo.confirmed = true;
$$ language sql;

View File

@ -1,30 +0,0 @@
-- updates_chart_repository updates the provided chart repository in the
-- database.
create or replace function update_chart_repository(p_user_id uuid, p_chart_repository jsonb)
returns void as $$
declare
v_owner_user_id uuid;
v_owner_organization_name text;
begin
-- Get user or organization owning the chart repository
select cr.user_id, o.name into v_owner_user_id, v_owner_organization_name
from chart_repository cr
left join organization o using (organization_id)
where cr.name = p_chart_repository->>'name';
-- Check if the user doing the request is the owner or belongs to the
-- organization which owns it
if v_owner_organization_name is not null then
if not user_belongs_to_organization(p_user_id, v_owner_organization_name) then
raise insufficient_privilege;
end if;
elsif v_owner_user_id <> p_user_id then
raise insufficient_privilege;
end if;
update chart_repository set
display_name = nullif(p_chart_repository->>'display_name', ''),
url = p_chart_repository->>'url'
where name = p_chart_repository->>'name';
end
$$ language plpgsql;

View File

@ -11,7 +11,7 @@ begin
raise insufficient_privilege;
end if;
-- Last user of an organization cannot leave it
-- Last member of an organization cannot leave it
select count(*) into v_users_in_organization
from user__organization uo
join organization o using (organization_id)

View File

@ -5,27 +5,21 @@ returns setof json as $$
declare
v_package_id uuid;
v_package_name text := p_input->>'package_name';
v_chart_repository_name text := p_input->>'chart_repository_name';
v_repository_name text := p_input->>'repository_name';
begin
if p_input->>'package_id' <> '' then
v_package_id = p_input->>'package_id';
elsif v_chart_repository_name <> '' then
else
select p.package_id into v_package_id
from package p
join chart_repository r using (chart_repository_id)
where r.name = v_chart_repository_name
and p.normalized_name = v_package_name;
else
select package_id into v_package_id
from package
where normalized_name = v_package_name
and chart_repository_id is null;
join repository r using (repository_id)
where p.normalized_name = v_package_name
and r.name = v_repository_name;
end if;
return query
select json_build_object(
'package_id', p.package_id,
'kind', p.package_kind_id,
'name', p.name,
'normalized_name', p.normalized_name,
'logo_image_id', p.logo_image_id,
@ -60,25 +54,21 @@ begin
join package__maintainer pm using (maintainer_id)
where pm.package_id = v_package_id
),
'user_alias', u.alias,
'organization_name', o.name,
'organization_display_name', o.display_name,
'chart_repository', (select nullif(
jsonb_build_object(
'chart_repository_id', r.chart_repository_id,
'name', r.name,
'display_name', r.display_name,
'url', r.url
),
'{"url": null, "name": null, "display_name": null, "chart_repository_id": null}'::jsonb
))
'repository', jsonb_build_object(
'repository_id', r.repository_id,
'kind', r.repository_kind_id,
'name', r.name,
'display_name', r.display_name,
'user_alias', u.alias,
'organization_name', o.name,
'organization_display_name', o.display_name
)
)
from package p
join snapshot s using (package_id)
left join chart_repository r using (chart_repository_id)
left join "user" u on p.user_id = u.user_id or r.user_id = u.user_id
left join organization o
on p.organization_id = o.organization_id or r.organization_id = o.organization_id
join repository r using (repository_id)
left join "user" u using (user_id)
left join organization o using (organization_id)
where p.package_id = v_package_id
and
case when p_input->>'version' <> '' then

View File

@ -4,7 +4,6 @@ create or replace function get_package_summary(p_package_id uuid)
returns setof json as $$
select json_build_object(
'package_id', p.package_id,
'kind', p.package_kind_id,
'name', p.name,
'normalized_name', p.normalized_name,
'logo_image_id', p.logo_image_id,
@ -16,23 +15,21 @@ returns setof json as $$
'deprecated', s.deprecated,
'signed', s.signed,
'created_at', floor(extract(epoch from s.created_at)),
'user_alias', u.alias,
'organization_name', o.name,
'organization_display_name', o.display_name,
'chart_repository', (select nullif(
jsonb_build_object(
'chart_repository_id', r.chart_repository_id,
'name', r.name,
'display_name', r.display_name
),
'{"chart_repository_id": null, "name": null, "display_name": null}'::jsonb
))
'repository', jsonb_build_object(
'repository_id', r.repository_id,
'kind', r.repository_kind_id,
'name', r.name,
'display_name', r.display_name,
'user_alias', u.alias,
'organization_name', o.name,
'organization_display_name', o.display_name
)
)
from package p
join snapshot s using (package_id)
left join chart_repository r using (chart_repository_id)
left join "user" u on p.user_id = u.user_id or r.user_id = u.user_id
left join organization o on p.organization_id = o.organization_id or r.organization_id = o.organization_id
join repository r using (repository_id)
left join "user" u using (user_id)
left join organization o using (organization_id)
where p.package_id = p_package_id
and s.version = p.latest_version;
$$ language sql;

View File

@ -13,44 +13,16 @@ declare
v_description text := nullif(p_pkg->>'description', '');
v_keywords text[] := (select (array(select jsonb_array_elements_text(nullif(p_pkg->'keywords', 'null'::jsonb))))::text[]);
v_version text := p_pkg->>'version';
v_package_kind_id int := (p_pkg->>'kind')::int;
v_user_id uuid := nullif(p_pkg->>'user_id', '')::uuid;
v_organization_id uuid := nullif(p_pkg->>'organization_id', '')::uuid;
v_chart_repository_id uuid := ((p_pkg->'chart_repository')->>'chart_repository_id')::uuid;
v_repository_id uuid := ((p_pkg->'repository')->>'repository_id')::uuid;
v_maintainer jsonb;
v_maintainer_id uuid;
v_created_at timestamptz;
begin
-- Check if a package with the same name and kind but a different owner
-- already exists.
-- NOTE: packages of kind Helm Chart are allowed to have the same name when
-- they belong to different repositories as the repo acts as a namespace.
perform
from package
where package_kind_id = v_package_kind_id
and name = v_name
and chart_repository_id is null
and (
user_id <> v_user_id
or organization_id <> v_organization_id
or (user_id is null and v_user_id is not null)
or (organization_id is null and v_organization_id is not null)
);
if found then
raise unique_violation;
end if;
-- Get package's latest version before registration, if available
select latest_version into v_previous_latest_version
from package
where package_kind_id = v_package_kind_id
and name = v_name
and
case when v_chart_repository_id is null then
chart_repository_id is null
else
chart_repository_id = v_chart_repository_id
end;
where name = v_name
and repository_id = v_repository_id;
-- Package
insert into package (
@ -59,27 +31,16 @@ begin
logo_image_id,
latest_version,
tsdoc,
package_kind_id,
user_id,
organization_id,
chart_repository_id
repository_id
) values (
v_name,
nullif(p_pkg->>'logo_url', ''),
nullif(p_pkg->>'logo_image_id', '')::uuid,
v_version,
generate_package_tsdoc(v_name, v_display_name, v_description, v_keywords),
v_package_kind_id,
v_user_id,
v_organization_id,
v_chart_repository_id
v_repository_id
)
on conflict (
coalesce(chart_repository_id, '99999999-9999-9999-9999-999999999999'),
package_kind_id,
name
)
do update
on conflict (repository_id, name) do update
set
name = excluded.name,
logo_url = excluded.logo_url,
@ -132,12 +93,7 @@ begin
select package_id into v_package_id
from package
where name = v_name
and
case when v_chart_repository_id is null then
chart_repository_id is null
else
chart_repository_id = v_chart_repository_id
end;
and repository_id = v_repository_id;
end if;
-- Package snapshot

View File

@ -3,29 +3,27 @@
create or replace function search_packages(p_input jsonb)
returns setof json as $$
declare
v_package_kinds int[];
v_repository_kinds int[];
v_users text[];
v_orgs text[];
v_chart_repositories text[];
v_repositories text[];
v_facets boolean := (p_input->>'facets')::boolean;
v_tsquery tsquery := websearch_to_tsquery(p_input->>'text');
begin
-- Prepare filters for later use
select array_agg(e::int) into v_package_kinds
from jsonb_array_elements_text(p_input->'package_kinds') e;
select array_agg(e::int) into v_repository_kinds
from jsonb_array_elements_text(p_input->'repository_kinds') e;
select array_agg(e::text) into v_users
from jsonb_array_elements_text(p_input->'users') e;
select array_agg(e::text) into v_orgs
from jsonb_array_elements_text(p_input->'orgs') e;
select array_agg(e::text) into v_chart_repositories
from jsonb_array_elements_text(p_input->'chart_repositories') e;
select array_agg(e::text) into v_repositories
from jsonb_array_elements_text(p_input->'repositories') e;
return query
with packages_applying_text_and_deprecated_filters as (
select
p.package_id,
p.package_kind_id,
pk.name as package_kind_name,
p.name,
p.normalized_name,
p.logo_image_id,
@ -38,19 +36,20 @@ begin
s.deprecated,
s.signed,
s.created_at,
r.repository_id,
r.repository_kind_id,
rk.name as repository_kind_name,
r.name as repository_name,
r.display_name as repository_display_name,
u.alias as user_alias,
o.name as organization_name,
o.display_name as organization_display_name,
r.chart_repository_id as chart_repository_id,
r.name as chart_repository_name,
r.display_name as chart_repository_display_name
o.display_name as organization_display_name
from package p
join package_kind pk using (package_kind_id)
join snapshot s using (package_id)
left join chart_repository r using (chart_repository_id)
left join "user" u on p.user_id = u.user_id or r.user_id = u.user_id
left join organization o
on p.organization_id = o.organization_id or r.organization_id = o.organization_id
join repository r using (repository_id)
join repository_kind rk using (repository_kind_id)
left join "user" u using (user_id)
left join organization o using (organization_id)
where s.version = p.latest_version
and
case when p_input ? 'text' and p_input->>'text' <> '' then
@ -65,8 +64,8 @@ begin
), packages_applying_all_filters as (
select * from packages_applying_text_and_deprecated_filters
where
case when cardinality(v_package_kinds) > 0
then package_kind_id = any(v_package_kinds) else true end
case when cardinality(v_repository_kinds) > 0
then repository_kind_id = any(v_repository_kinds) else true end
and
case when cardinality(v_users) > 0
then user_alias = any(v_users) else true end
@ -74,8 +73,8 @@ begin
case when cardinality(v_orgs) > 0
then organization_name = any(v_orgs) else true end
and
case when cardinality(v_chart_repositories) > 0
then chart_repository_name = any(v_chart_repositories) else true end
case when cardinality(v_repositories) > 0
then repository_name = any(v_repositories) else true end
and
case when p_input ? 'deprecated' and (p_input->>'deprecated')::boolean = true then
true
@ -89,7 +88,6 @@ begin
'packages', (
select coalesce(json_agg(json_build_object(
'package_id', package_id,
'kind', package_kind_id,
'name', name,
'normalized_name', normalized_name,
'logo_image_id', logo_image_id,
@ -101,17 +99,15 @@ begin
'deprecated', deprecated,
'signed', signed,
'created_at', floor(extract(epoch from created_at)),
'user_alias', user_alias,
'organization_name', organization_name,
'organization_display_name', organization_display_name,
'chart_repository', (select nullif(
jsonb_build_object(
'chart_repository_id', chart_repository_id,
'name', chart_repository_name,
'display_name', chart_repository_display_name
),
'{"chart_repository_id": null, "name": null, "display_name": null}'::jsonb
))
'repository', jsonb_build_object(
'repository_id', repository_id,
'kind', repository_kind_id,
'name', repository_name,
'display_name', repository_display_name,
'user_alias', user_alias,
'organization_name', organization_name,
'organization_display_name', organization_display_name
)
)), '[]')
from (
select
@ -146,7 +142,7 @@ begin
from packages_applying_text_and_deprecated_filters
where organization_name is not null
group by organization_name, organization_display_name
order by total desc
order by total desc, organization_name asc
) as breakdown
)
)
@ -168,7 +164,7 @@ begin
from packages_applying_text_and_deprecated_filters
where user_alias is not null
group by user_alias
order by total desc
order by total desc, user_alias asc
) as breakdown
)
)
@ -179,40 +175,40 @@ begin
'filter_key', 'kind',
'options', (
select coalesce(json_agg(json_build_object(
'id', package_kind_id,
'name', package_kind_name,
'id', repository_kind_id,
'name', repository_kind_name,
'total', total
)), '[]')
from (
select
package_kind_id,
package_kind_name,
repository_kind_id,
repository_kind_name,
count(*) as total
from packages_applying_text_and_deprecated_filters
group by package_kind_id, package_kind_name
order by total desc
group by repository_kind_id, repository_kind_name
order by total desc, repository_kind_name asc
) as breakdown
)
)
),
(
select json_build_object(
'title', 'Chart Repository',
'title', 'Repository',
'filter_key', 'repo',
'options', (
select coalesce(json_agg(json_build_object(
'id', chart_repository_name,
'name', initcap(chart_repository_name),
'id', repository_name,
'name', initcap(repository_name),
'total', total
)), '[]')
from (
select
chart_repository_name,
repository_name,
count(*) as total
from packages_applying_text_and_deprecated_filters
where chart_repository_name is not null
group by chart_repository_name
order by total desc
where repository_name is not null
group by repository_name
order by total desc, repository_name asc
) as breakdown
)
)

View File

@ -5,17 +5,15 @@ declare
v_package_id uuid;
v_latest_version text;
v_snapshots_count int;
v_chart_repository_id text := (p_pkg->'chart_repository')->>'chart_repository_id';
v_semver_regexp text := '(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?';
begin
-- Get package id
-- Get some package details
select p.package_id, p.latest_version, count(s.version)
into v_package_id, v_latest_version, v_snapshots_count
from package p
join snapshot s using (package_id)
where p.package_kind_id = (p_pkg->>'kind')::int
and p.name = p_pkg->>'name'
and chart_repository_id = nullif(v_chart_repository_id, '')::uuid
where p.name = p_pkg->>'name'
and repository_id = ((p_pkg->'repository')->>'repository_id')::uuid
group by p.package_id, p.latest_version;
if not found then
return;

View File

@ -1,8 +1,8 @@
-- add_chart_repository adds the provided chart repository to the database.
create or replace function add_chart_repository(
-- add_repository adds the provided repository to the database.
create or replace function add_repository(
p_user_id uuid,
p_org_name text,
p_chart_repository jsonb
p_repository jsonb
) returns void as $$
declare
v_owner_user_id uuid;
@ -17,16 +17,18 @@ begin
v_owner_user_id = p_user_id;
end if;
insert into chart_repository (
insert into repository (
name,
display_name,
url,
repository_kind_id,
user_id,
organization_id
) values (
p_chart_repository->>'name',
nullif(p_chart_repository->>'display_name', ''),
p_chart_repository->>'url',
p_repository->>'name',
nullif(p_repository->>'display_name', ''),
p_repository->>'url',
(p_repository->>'kind')::int,
v_owner_user_id,
v_owner_organization_id
);

View File

@ -1,16 +1,15 @@
-- delete_chart_repository deletes the provided chart repository from the
-- database.
create or replace function delete_chart_repository(p_user_id uuid, p_chart_repository_name text)
-- delete_repository deletes the provided repository from the database.
create or replace function delete_repository(p_user_id uuid, p_repository_name text)
returns void as $$
declare
v_owner_user_id uuid;
v_owner_organization_name text;
begin
-- Get user or organization owning the chart repository
select cr.user_id, o.name into v_owner_user_id, v_owner_organization_name
from chart_repository cr
-- Get user or organization owning the repository
select r.user_id, o.name into v_owner_user_id, v_owner_organization_name
from repository r
left join organization o using (organization_id)
where cr.name = p_chart_repository_name;
where r.name = p_repository_name;
-- Check if the user doing the request is the owner or belongs to the
-- organization which owns it
@ -22,6 +21,6 @@ begin
raise insufficient_privilege;
end if;
delete from chart_repository where name = p_chart_repository_name;
delete from repository where name = p_repository_name;
end
$$ language plpgsql;

View File

@ -0,0 +1,21 @@
-- get_org_repositories returns all available repositories that belong to the
-- provided organization as a json array. The user provided must belong to the
-- organization used.
create or replace function get_org_repositories(p_user_id uuid, p_org_name text)
returns setof json as $$
select coalesce(json_agg(json_build_object(
'repository_id', r.repository_id,
'name', r.name,
'display_name', r.display_name,
'url', r.url,
'last_tracking_ts', floor(extract(epoch from r.last_tracking_ts)),
'last_tracking_errors', r.last_tracking_errors,
'kind', r.repository_kind_id
)), '[]')
from repository r
join organization o using (organization_id)
join user__organization uo using (organization_id)
where o.name = p_org_name
and uo.user_id = p_user_id
and uo.confirmed = true;
$$ language sql;

View File

@ -0,0 +1,13 @@
-- get_repositories_by_kind returns all available repositories of a given kind
-- as a json array.
create or replace function get_repositories_by_kind(p_kind int)
returns setof json as $$
select coalesce(json_agg(json_build_object(
'repository_id', repository_id,
'name', name,
'display_name', display_name,
'url', url
)), '[]')
from repository
where repository_kind_id = p_kind;
$$ language sql;

View File

@ -0,0 +1,14 @@
-- get_repository_by_name returns the repository identified by the name
-- provided as a json object.
create or replace function get_repository_by_name(p_name text)
returns setof json as $$
select json_build_object(
'repository_id', repository_id,
'name', name,
'display_name', display_name,
'url', url,
'kind', repository_kind_id
)
from repository
where name = p_name;
$$ language sql;

View File

@ -0,0 +1,9 @@
-- get_repository_packages_digest returns the digest of all packages that
-- belong to the repository identified by the id provided.
create or replace function get_repository_packages_digest(p_repository_id uuid)
returns setof json as $$
select coalesce(json_object_agg(format('%s@%s', p.name, s.version), s.digest), '{}')
from package p
join snapshot s using (package_id)
where p.repository_id = p_repository_id;
$$ language sql;

View File

@ -1,16 +1,17 @@
-- get_user_chart_repositories returns all available chart repositories that
-- belong to the provided user as a json array.
create or replace function get_user_chart_repositories(p_user_id uuid)
-- get_repositories returns all available repositories that belong to the
-- provided user as a json array.
create or replace function get_user_repositories(p_user_id uuid)
returns setof json as $$
select coalesce(json_agg(json_build_object(
'chart_repository_id', chart_repository_id,
'repository_id', repository_id,
'name', name,
'display_name', display_name,
'url', url,
'kind', repository_kind_id,
'last_tracking_ts', floor(extract(epoch from last_tracking_ts)),
'last_tracking_errors', last_tracking_errors
)), '[]')
from chart_repository
from repository
where user_id is not null
and user_id = p_user_id;
$$ language sql;

View File

@ -1,7 +1,7 @@
-- transfer_chart_repository transfers the ownership of the provided chart
-- repository to the requesting user or an organization he belongs to.
create or replace function transfer_chart_repository(
p_chart_repository_name text,
-- transfer_repository transfers the ownership of the provided repository to
-- to the requesting user or an organization he belongs to.
create or replace function transfer_repository(
p_repository_name text,
p_user_id uuid,
p_org_name text
) returns void as $$
@ -9,11 +9,11 @@ declare
v_owner_user_id uuid;
v_owner_organization_name text;
begin
-- Get user or organization owning the chart repository
select cr.user_id, o.name into v_owner_user_id, v_owner_organization_name
from chart_repository cr
-- Get user or organization owning the repository
select r.user_id, o.name into v_owner_user_id, v_owner_organization_name
from repository r
left join organization o using (organization_id)
where cr.name = p_chart_repository_name;
where r.name = p_repository_name;
-- Check if the user doing the request is the owner or belongs to the
-- organization which owns it
@ -25,25 +25,25 @@ begin
raise insufficient_privilege;
end if;
-- When transferring a chart repository to an organization, check the
-- requesting user belongs to it
-- When transferring a repository to an organization, check the requesting
-- user belongs to it
if p_org_name is not null and not user_belongs_to_organization(p_user_id, p_org_name) then
raise insufficient_privilege;
end if;
-- Transfer repository ownership
if p_org_name is null then
update chart_repository set
update repository set
user_id = p_user_id,
organization_id = null
where name = p_chart_repository_name;
where name = p_repository_name;
else
update chart_repository set
update repository set
organization_id = (
select organization_id from organization where name = p_org_name
),
user_id = null
where name = p_chart_repository_name;
where name = p_repository_name;
end if;
end
$$ language plpgsql;

View File

@ -0,0 +1,29 @@
-- updates_repository updates the provided repository in the database.
create or replace function update_repository(p_user_id uuid, p_repository jsonb)
returns void as $$
declare
v_owner_user_id uuid;
v_owner_organization_name text;
begin
-- Get user or organization owning the repository
select r.user_id, o.name into v_owner_user_id, v_owner_organization_name
from repository r
left join organization o using (organization_id)
where r.name = p_repository->>'name';
-- Check if the user doing the request is the owner or belongs to the
-- organization which owns it
if v_owner_organization_name is not null then
if not user_belongs_to_organization(p_user_id, v_owner_organization_name) then
raise insufficient_privilege;
end if;
elsif v_owner_user_id <> p_user_id then
raise insufficient_privilege;
end if;
update repository set
display_name = nullif(p_repository->>'display_name', ''),
url = p_repository->>'url'
where name = p_repository->>'name';
end
$$ language plpgsql;

View File

@ -4,20 +4,17 @@ create or replace function get_user_subscriptions(p_user_id uuid)
returns setof json as $$
select coalesce(json_agg(json_build_object(
'package_id', package_id,
'kind', package_kind_id,
'name', name,
'normalized_name', normalized_name,
'logo_image_id', logo_image_id,
'user_alias', user_alias,
'organization_name', organization_name,
'organization_display_name', organization_display_name,
'chart_repository', (select nullif(
jsonb_build_object(
'name', chart_repository_name,
'display_name', chart_repository_display_name
),
'{"name": null, "display_name": null}'::jsonb
)),
'repository', jsonb_build_object(
'kind', repository_kind_id,
'name', repository_name,
'display_name', repository_display_name,
'user_alias', user_alias,
'organization_name', organization_name,
'organization_display_name', organization_display_name
),
'event_kinds', (
select json_agg(distinct(event_kind_id))
from subscription
@ -28,20 +25,19 @@ returns setof json as $$
from (
select
p.package_id,
p.package_kind_id,
p.name,
p.normalized_name,
p.logo_image_id,
r.repository_kind_id,
r.name as repository_name,
r.display_name as repository_display_name,
u.alias as user_alias,
o.name as organization_name,
o.display_name as organization_display_name,
r.name as chart_repository_name,
r.display_name as chart_repository_display_name
o.display_name as organization_display_name
from package p
left join chart_repository r using (chart_repository_id)
left join "user" u on p.user_id = u.user_id or r.user_id = u.user_id
left join organization o
on p.organization_id = o.organization_id or r.organization_id = o.organization_id
join repository r using (repository_id)
left join "user" u using (user_id)
left join organization o using (organization_id)
where p.package_id in (
select distinct(package_id) from subscription where user_id = p_user_id
)

View File

@ -47,29 +47,32 @@ create table if not exists session (
created_at timestamptz default current_timestamp not null
);
create table if not exists chart_repository (
chart_repository_id uuid primary key default gen_random_uuid(),
create table if not exists repository_kind (
repository_kind_id integer primary key,
name text not null check (name <> '')
);
insert into repository_kind values (0, 'Helm charts');
insert into repository_kind values (1, 'Falco rules');
insert into repository_kind values (2, 'OPA policies');
insert into repository_kind values (3, 'OLM operators');
create table if not exists repository (
repository_id uuid primary key default gen_random_uuid(),
name text not null check (name <> '') unique,
display_name text check (display_name <> ''),
url text not null check (url <> '') unique,
last_tracking_ts timestamptz,
last_tracking_errors text,
repository_kind_id integer not null default 0 references repository_kind on delete restrict,
user_id uuid references "user" on delete restrict,
organization_id uuid references organization on delete restrict,
check (user_id is null or organization_id is null)
check (user_id is not null or organization_id is not null)
);
create index chart_repository_user_id_idx on chart_repository (user_id);
create index chart_repository_organization_id_idx on chart_repository (organization_id);
create table if not exists package_kind (
package_kind_id integer primary key,
name text not null check (name <> '')
);
insert into package_kind values (0, 'Helm charts');
insert into package_kind values (1, 'Falco rules');
insert into package_kind values (2, 'OPA policies');
create index repository_repository_kind_id_idx on repository (repository_kind_id);
create index repository_user_id_idx on repository (user_id);
create index repository_organization_id_idx on repository (organization_id);
create table if not exists package (
package_id uuid primary key default gen_random_uuid(),
@ -80,27 +83,12 @@ create table if not exists package (
logo_image_id uuid,
stars integer not null default 0,
tsdoc tsvector,
package_kind_id integer not null references package_kind on delete restrict,
user_id uuid references "user" on delete restrict,
organization_id uuid references organization on delete restrict,
chart_repository_id uuid references chart_repository on delete cascade,
check (user_id is null or organization_id is null),
check (user_id is null or chart_repository_id is null),
check (organization_id is null or chart_repository_id is null),
check (package_kind_id <> 0 or chart_repository_id is not null)
repository_id uuid not null references repository on delete cascade,
unique (repository_id, name)
);
create index package_stars_idx on package (stars);
create index package_tsdoc_idx on package using gin (tsdoc);
create index package_package_kind_id_idx on package (package_kind_id);
create index package_user_id_idx on package (user_id);
create index package_organization_id_idx on package (organization_id);
create index package_chart_repository_id_idx on package (chart_repository_id);
create unique index package_unique_name_idx on package (
coalesce(chart_repository_id, '99999999-9999-9999-9999-999999999999'),
package_kind_id,
name
);
create index package_repository_id_idx on package (repository_id);
create table if not exists snapshot (
package_id uuid not null references package on delete cascade,

View File

@ -3,7 +3,7 @@ insert into "user" (user_id, alias, email, email_verified, password)
values ('00000000-0000-0000-0000-000000000001', 'demo', 'demo@artifacthub.io', true, '$2a$10$FRAFMqDgJYgKEIrW8Y3Pqu7m5uFjtGxNAjlOtXA1iiFGGH7NycLIO');
-- Register Helm repositories
insert into chart_repository (name, url, user_id)
values ('stable','https://kubernetes-charts.storage.googleapis.com', '00000000-0000-0000-0000-000000000001');
insert into chart_repository (name, url, user_id)
values ('incubator','https://kubernetes-charts-incubator.storage.googleapis.com', '00000000-0000-0000-0000-000000000001');
insert into repository (name, url, repository_kind_id, user_id)
values ('stable','https://kubernetes-charts.storage.googleapis.com', 0, '00000000-0000-0000-0000-000000000001');
insert into repository (name, url, repository_kind_id, user_id)
values ('incubator','https://kubernetes-charts-incubator.storage.googleapis.com', 0, '00000000-0000-0000-0000-000000000001');

View File

@ -1,44 +0,0 @@
-- Start transaction and plan tests
begin;
select plan(2);
-- No repositories at this point
select is(
get_chart_repositories()::jsonb,
'[]'::jsonb,
'With no repositories an empty json array is returned'
);
-- Seed some chart repositories
insert into chart_repository (chart_repository_id, name, display_name, url)
values ('00000000-0000-0000-0000-000000000001', 'repo1', 'Repo 1', 'https://repo1.com');
insert into chart_repository (chart_repository_id, name, display_name, url)
values ('00000000-0000-0000-0000-000000000002', 'repo2', 'Repo 2', 'https://repo2.com');
insert into chart_repository (chart_repository_id, name, display_name, url)
values ('00000000-0000-0000-0000-000000000003', 'repo3', 'Repo 3', 'https://repo3.com');
-- Run some tests
select is(
get_chart_repositories()::jsonb,
'[{
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"name": "repo1",
"display_name": "Repo 1",
"url": "https://repo1.com"
}, {
"chart_repository_id": "00000000-0000-0000-0000-000000000002",
"name": "repo2",
"display_name": "Repo 2",
"url": "https://repo2.com"
}, {
"chart_repository_id": "00000000-0000-0000-0000-000000000003",
"name": "repo3",
"display_name": "Repo 3",
"url": "https://repo3.com"
}]'::jsonb,
'Repositories are returned as a json array of objects'
);
-- Finish tests and rollback transaction
select * from finish();
rollback;

View File

@ -1,29 +0,0 @@
-- Start transaction and plan tests
begin;
select plan(2);
-- Non existing repository
select is_empty(
$$ select get_chart_repository_by_name('repo1') $$,
'If repository requested does not exist no rows are returned'
);
-- Seed one chart repository
insert into chart_repository (chart_repository_id, name, display_name, url)
values ('00000000-0000-0000-0000-000000000001', 'repo1', 'Repo 1', 'https://repo1.com');
-- One repository has just been seeded
select is(
get_chart_repository_by_name('repo1')::jsonb,
'{
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"name": "repo1",
"display_name": "Repo 1",
"url": "https://repo1.com"
}'::jsonb,
'Repository just seeded is returned as a json object'
);
-- Finish tests and rollback transaction
select * from finish();
rollback;

View File

@ -3,8 +3,10 @@ begin;
select plan(4);
-- Declare some variables
\set event1ID '00000000-0000-0000-0000-000000000001'
\set user1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set package1ID '00000000-0000-0000-0000-000000000001'
\set event1ID '00000000-0000-0000-0000-000000000001'
-- No pending events available yet
select is_empty(
@ -13,17 +15,11 @@ select is_empty(
);
-- Seed some data
insert into package (
package_id,
name,
latest_version,
package_kind_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
1
);
insert into "user" (user_id, alias, email) values (:'user1ID', 'user1', 'user1@email.com');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (package_id, name, latest_version, repository_id)
values (:'package1ID', 'Package 1', '1.0.0', :'repo1ID');
insert into event (event_id, package_version, package_id, event_kind_id)
values (:'event1ID', '1.0.0', :'package1ID', 0);
savepoint before_getting_event;

View File

@ -3,27 +3,20 @@ begin;
select plan(3);
-- Declare some variables
\set user1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set package1ID '00000000-0000-0000-0000-000000000001'
\set event1ID '00000000-0000-0000-0000-000000000001'
\set user1ID '00000000-0000-0000-0000-000000000001'
\set webhook1ID '00000000-0000-0000-0000-000000000001'
-- Seed some data
insert into package (
package_id,
name,
latest_version,
package_kind_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
1
);
insert into "user" (user_id, alias, email) values (:'user1ID', 'user1', 'user1@email.com');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (package_id, name, latest_version, repository_id)
values (:'package1ID', 'Package 1', '1.0.0', :'repo1ID');
insert into event (event_id, package_version, package_id, event_kind_id)
values (:'event1ID', '1.0.0', :'package1ID', 0);
insert into "user" (user_id, alias, email)
values (:'user1ID', 'user1', 'user1@email.com');
insert into webhook (
webhook_id,
name,

View File

@ -4,6 +4,7 @@ select plan(3);
-- Declare some variables
\set user1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set webhook1ID '00000000-0000-0000-0000-000000000001'
\set package1ID '00000000-0000-0000-0000-000000000001'
\set event1ID '00000000-0000-0000-0000-000000000001'
@ -18,6 +19,10 @@ select is_empty(
-- Seed some data
insert into "user" (user_id, alias, email) values (:'user1ID', 'user1', 'user1@email.com');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (package_id, name, latest_version, repository_id)
values (:'package1ID', 'Package 1', '1.0.0', :'repo1ID');
insert into webhook (
webhook_id,
name,
@ -37,17 +42,6 @@ insert into webhook (
true,
:'user1ID'
);
insert into package (
package_id,
name,
latest_version,
package_kind_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
1
);
insert into event (event_id, package_version, package_id, event_kind_id)
values (:'event1ID', '1.0.0', :'package1ID', 0);

View File

@ -4,23 +4,17 @@ select plan(2);
-- Declare some variables
\set user1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set package1ID '00000000-0000-0000-0000-000000000001'
\set event1ID '00000000-0000-0000-0000-000000000001'
\set notification1ID '00000000-0000-0000-0000-000000000001'
-- Seed some data
insert into "user" (user_id, alias, email) values (:'user1ID', 'user1', 'user1@email.com');
insert into package (
package_id,
name,
latest_version,
package_kind_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
1
);
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (package_id, name, latest_version, repository_id)
values (:'package1ID', 'Package 1', '1.0.0', :'repo1ID');
insert into event (event_id, package_version, package_id, event_kind_id)
values (:'event1ID', '1.0.0', :'package1ID', 0);
insert into notification (notification_id, event_id, user_id)

View File

@ -6,6 +6,7 @@ select plan(5);
\set org1ID '00000000-0000-0000-0000-000000000001'
\set user1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set repo2ID '00000000-0000-0000-0000-000000000002'
\set package1ID '00000000-0000-0000-0000-000000000001'
\set package2ID '00000000-0000-0000-0000-000000000002'
\set maintainer1ID '00000000-0000-0000-0000-000000000001'
@ -18,7 +19,7 @@ select is_empty(
$$
select get_package('{
"package_name": "package1",
"chart_repository_name": "repo1"
"repository_name": "repo1"
}')
$$,
'If package requested does not exist no rows are returned'
@ -28,8 +29,10 @@ select is_empty(
insert into organization (organization_id, name, display_name, description, home_url)
values (:'org1ID', 'org1', 'Organization 1', 'Description 1', 'https://org1.com');
insert into "user" (user_id, alias, email) values (:'user1ID', 'user1', 'user1@email.com');
insert into chart_repository (chart_repository_id, name, display_name, url, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', :'user1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, organization_id)
values (:'repo2ID', 'repo2', 'Repo 2', 'https://repo2.com', 0, :'org1ID');
insert into maintainer (maintainer_id, name, email)
values (:'maintainer1ID', 'name1', 'email1');
insert into maintainer (maintainer_id, name, email)
@ -39,14 +42,12 @@ insert into package (
name,
latest_version,
logo_image_id,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
:'image1ID',
0,
:'repo1ID'
);
insert into package__maintainer (package_id, maintainer_id)
@ -118,15 +119,13 @@ insert into package (
name,
latest_version,
logo_image_id,
package_kind_id,
organization_id
repository_id
) values (
:'package2ID',
'package2',
'1.0.0',
:'image2ID',
1,
:'org1ID'
:'repo2ID'
);
insert into snapshot (
package_id,
@ -155,7 +154,6 @@ select is(
}')::jsonb,
'{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "Package 1",
"normalized_name": "package-1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -204,14 +202,14 @@ select is(
"email": "email2"
}
],
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1",
"url": "https://repo1.com"
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
}
}'::jsonb,
'Last package1 version is returned as a json object'
@ -219,11 +217,10 @@ select is(
select is(
get_package('{
"package_name": "package-1",
"chart_repository_name": "repo1"
"repository_name": "repo1"
}')::jsonb,
'{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "Package 1",
"normalized_name": "package-1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -272,14 +269,14 @@ select is(
"email": "email2"
}
],
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1",
"url": "https://repo1.com"
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
}
}'::jsonb,
'Last package1 version is returned as a json object'
@ -287,12 +284,11 @@ select is(
select is(
get_package('{
"package_name": "package-1",
"chart_repository_name": "repo1",
"repository_name": "repo1",
"version": "0.0.9"
}')::jsonb,
'{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "Package 1",
"normalized_name": "package-1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -341,25 +337,25 @@ select is(
"email": "email2"
}
],
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1",
"url": "https://repo1.com"
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
}
}'::jsonb,
'Requested package version is returned as a json object'
);
select is(
get_package('{
"package_name": "package2"
"package_name": "package2",
"repository_name": "repo2"
}')::jsonb,
'{
"package_id": "00000000-0000-0000-0000-000000000002",
"kind": 1,
"name": "package2",
"normalized_name": "package2",
"logo_image_id": "00000000-0000-0000-0000-000000000002",
@ -386,10 +382,15 @@ select is(
}
],
"maintainers": null,
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1",
"chart_repository": null
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000002",
"kind": 0,
"name": "repo2",
"display_name": "Repo 2",
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1"
}
}'::jsonb,
'Last package2 version is returned as a json object'
);

View File

@ -14,23 +14,21 @@ select plan(4);
-- Seed some data
insert into "user" (user_id, alias, email) values (:'user1ID', 'user1', 'user1@email.com');
insert into "user" (user_id, alias, email) values (:'user2ID', 'user2', 'user2@email.com');
insert into chart_repository (chart_repository_id, name, display_name, url, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', :'user1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (
package_id,
name,
latest_version,
logo_image_id,
stars,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
:'image1ID',
10,
0,
:'repo1ID'
);
insert into user_starred_package(user_id, package_id) values (:'user1ID', :'package1ID');

View File

@ -11,23 +11,21 @@ select plan(2);
-- Seed some data
insert into organization (organization_id, name, display_name, description, home_url)
values (:'org1ID', 'org1', 'Organization 1', 'Description 1', 'https://org1.com');
insert into chart_repository (chart_repository_id, name, display_name, url, organization_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', :'org1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, organization_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'org1ID');
insert into package (
package_id,
name,
latest_version,
logo_image_id,
stars,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package1ID',
'package1',
'1.0.0',
:'image1ID',
10,
0,
:'repo1ID'
);
insert into snapshot (
@ -55,7 +53,6 @@ select is(
get_package_summary(:'package1ID')::jsonb,
'{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "package1",
"normalized_name": "package1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -67,13 +64,14 @@ select is(
"deprecated": false,
"signed": false,
"created_at": 1592299234,
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1",
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1"
"display_name": "Repo 1",
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1"
}
}'::jsonb,
'Package1 details should be returned as a json object'

View File

@ -6,6 +6,7 @@ select plan(2);
\set user1ID '00000000-0000-0000-0000-000000000001'
\set user2ID '00000000-0000-0000-0000-000000000002'
\set org1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set package1ID '00000000-0000-0000-0000-000000000001'
\set package2ID '00000000-0000-0000-0000-000000000002'
\set image1ID '00000000-0000-0000-0000-000000000001'
@ -16,22 +17,22 @@ insert into "user" (user_id, alias, email) values (:'user1ID', 'user1', 'user1@e
insert into "user" (user_id, alias, email) values (:'user2ID', 'user2', 'user2@email.com');
insert into organization (organization_id, name, display_name, description, home_url)
values (:'org1ID', 'org1', 'Organization 1', 'Description 1', 'https://org1.com');
insert into repository (repository_id, name, display_name, url, repository_kind_id, organization_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'org1ID');
insert into package (
package_id,
name,
latest_version,
logo_image_id,
stars,
package_kind_id,
organization_id
repository_id
) values (
:'package1ID',
'package1',
'1.0.0',
:'image1ID',
10,
1,
:'org1ID'
:'repo1ID'
);
insert into snapshot (
package_id,
@ -77,16 +78,14 @@ insert into package (
latest_version,
logo_image_id,
stars,
package_kind_id,
organization_id
repository_id
) values (
:'package2ID',
'package2',
'1.0.0',
:'image2ID',
11,
1,
:'org1ID'
:'repo1ID'
);
insert into snapshot (
package_id,
@ -118,7 +117,6 @@ select is(
get_packages_starred_by_user(:'user1ID')::jsonb,
'[{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 1,
"name": "package1",
"normalized_name": "package1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -130,10 +128,15 @@ select is(
"deprecated": null,
"signed": null,
"created_at": 1592299234,
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1",
"chart_repository": null
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1",
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1"
}
}]'::jsonb,
'Package1 expected as is the only package starred by user1'
);

View File

@ -3,6 +3,7 @@ begin;
select plan(2);
-- Declare some variables
\set user1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set package1ID '00000000-0000-0000-0000-000000000001'
\set package2ID '00000000-0000-0000-0000-000000000002'
@ -20,21 +21,21 @@ select is(
);
-- Seed some packages
insert into chart_repository (chart_repository_id, name, display_name, url)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com');
insert into "user" (user_id, alias, email)
values (:'user1ID', 'user1', 'user1@email.com');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (
package_id,
name,
latest_version,
logo_image_id,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package1ID',
'package1',
'1.0.0',
:'image1ID',
0,
:'repo1ID'
);
insert into snapshot (
@ -80,14 +81,12 @@ insert into package (
name,
latest_version,
logo_image_id,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package2ID',
'package2',
'1.0.0',
:'image2ID',
0,
:'repo1ID'
);
insert into snapshot (

View File

@ -23,26 +23,24 @@ select is(
-- Seed some data
insert into organization (organization_id, name, display_name, description, home_url)
values (:'org1ID', 'org1', 'Organization 1', 'Description 1', 'https://org1.com');
insert into chart_repository (chart_repository_id, name, display_name, url, organization_id)
values (:'repo2ID', 'repo2', 'Repo 2', 'https://repo2.com', :'org1ID');
insert into chart_repository (chart_repository_id, name, display_name, url)
values (:'repo3ID', 'repo3', 'Repo 3', 'https://repo3.com');
insert into repository (repository_id, name, display_name, url, repository_kind_id, organization_id)
values (:'repo2ID', 'repo2', 'Repo 2', 'https://repo2.com', 0, :'org1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, organization_id)
values (:'repo3ID', 'repo3', 'Repo 3', 'https://repo3.com', 0, :'org1ID');
insert into package (
package_id,
name,
latest_version,
logo_image_id,
stars,
package_kind_id,
organization_id
repository_id
) values (
:'package1ID',
'package1',
'1.0.0',
:'image1ID',
10,
1,
:'org1ID'
:'repo2ID'
);
insert into snapshot (
package_id,
@ -72,14 +70,12 @@ insert into package (
name,
latest_version,
stars,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package2ID',
'package2',
'1.0.0',
5,
0,
:'repo2ID'
);
insert into snapshot (
@ -110,14 +106,12 @@ insert into package (
name,
latest_version,
logo_image_id,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package3ID',
'package3',
'1.0.0',
:'image3ID',
0,
:'repo3ID'
);
insert into snapshot (
@ -154,7 +148,6 @@ select is(
'[
{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 1,
"name": "package1",
"normalized_name": "package1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -166,10 +159,15 @@ select is(
"deprecated": false,
"signed": false,
"created_at": 1592299234,
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1",
"chart_repository": null
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000002",
"kind": 0,
"name": "repo2",
"display_name": "Repo 2",
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1"
}
}
]'::jsonb,
'One random package expected (package1)'

View File

@ -1,6 +1,6 @@
-- Start transaction and plan tests
begin;
select plan(20);
select plan(13);
-- Declare some variables
\set org1ID '00000000-0000-0000-0000-000000000001'
@ -10,14 +10,13 @@ select plan(20);
-- Seed some data
insert into organization (organization_id, name, display_name, description, home_url)
values (:'org1ID', 'org1', 'Organization 1', 'Description 1', 'https://org1.com');
insert into chart_repository (chart_repository_id, name, display_name, url)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com');
insert into "user" (user_id, alias, email) values (:'user1ID', 'user1', 'user1@email.com');
insert into repository (repository_id, name, display_name, url, repository_kind_id, organization_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'org1ID');
-- Register package
select register_package('
{
"kind": 0,
"name": "package1",
"logo_url": "logo_url",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -57,8 +56,8 @@ select register_package('
"email": "email2"
}
],
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001"
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001"
}
}
');
@ -69,8 +68,7 @@ select results_eq(
latest_version,
logo_url,
logo_image_id,
package_kind_id,
chart_repository_id
repository_id
from package
where name='package1'
$$,
@ -80,7 +78,6 @@ select results_eq(
'1.0.0',
'logo_url',
'00000000-0000-0000-0000-000000000001'::uuid,
0,
'00000000-0000-0000-0000-000000000001'::uuid
)
$$,
@ -161,7 +158,6 @@ select is_empty(
-- Register a new version of the package previously registered
select register_package('
{
"kind": 0,
"name": "package1",
"logo_url": "logo_url updated",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -182,8 +178,8 @@ select register_package('
"email": "email1"
}
],
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001"
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001"
}
}
');
@ -272,7 +268,6 @@ select isnt_empty(
-- Register an old version of the package previously registered
select register_package('
{
"kind": 0,
"name": "package1",
"display_name": "Package 1",
"description": "description",
@ -297,8 +292,8 @@ select register_package('
"email": "email2"
}
],
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001"
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001"
}
}
');
@ -374,145 +369,6 @@ select is_empty(
'No new release event should exist for package1 version 0.0.9'
);
-- Register package that belongs to an organization and check it succeeded
select register_package('
{
"kind": 1,
"name": "package3",
"display_name": "Package 3",
"description": "description",
"version": "1.0.0",
"organization_id": "00000000-0000-0000-0000-000000000001"
}
');
select results_eq(
$$
select
name,
latest_version,
package_kind_id,
organization_id,
chart_repository_id
from package
where name='package3'
$$,
$$
values (
'package3',
'1.0.0',
1,
'00000000-0000-0000-0000-000000000001'::uuid,
null::uuid
)
$$,
'Package3 that belongs to organization should exist'
);
select is_empty(
$$
select *
from event e
join package p using (package_id)
where p.name = 'package3'
and e.package_version = '1.0.0'
$$,
'No new release event should exist for first version of package3'
);
-- Register a new version of the package previously registered
select register_package('
{
"kind": 1,
"name": "package3",
"display_name": "Package 3",
"description": "description",
"version": "2.0.0",
"organization_id": "00000000-0000-0000-0000-000000000001"
}
');
select results_eq(
$$
select
name,
latest_version,
package_kind_id,
organization_id,
chart_repository_id
from package
where name='package3'
$$,
$$
values (
'package3',
'2.0.0',
1,
'00000000-0000-0000-0000-000000000001'::uuid,
null::uuid
)
$$,
'Package3 latest version should exist and its latest version should be 2.0.0'
);
select isnt_empty(
$$
select *
from event e
join package p using (package_id)
where p.name = 'package3'
and e.package_version = '2.0.0'
$$,
'New release event should exist for new version of package3'
);
-- Register a package with a name and kind already registered but with a different owner
select throws_ok(
$$
select register_package('
{
"kind": 1,
"name": "package3",
"display_name": "Package 3",
"description": "description",
"version": "3.0.0",
"organization_id": "00000000-0000-0000-0000-000000000002"
}
'::jsonb)
$$,
23505,
'unique_violation',
'Org2 should not be able to register package3 as it already exists and is owned by org1'
);
select throws_ok(
$$
select register_package('
{
"kind": 1,
"name": "package3",
"display_name": "Package 3",
"description": "description",
"version": "3.0.0",
"user_id": "00000000-0000-0000-0000-000000000001"
}
'::jsonb)
$$,
23505,
'unique_violation',
'User1 should not be able to register package3 as it already exists and is owned by org1'
);
select lives_ok(
$$
select register_package('
{
"kind": 2,
"name": "package3",
"display_name": "Package 3",
"description": "description",
"version": "3.0.0",
"user_id": "00000000-0000-0000-0000-000000000001"
}
'::jsonb)
$$,
'User1 should be able to register package3 now using a different package kind'
);
-- Finish tests and rollback transaction
select * from finish();
rollback;

View File

@ -7,6 +7,7 @@ select plan(20);
\set org1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set repo2ID '00000000-0000-0000-0000-000000000002'
\set repo3ID '00000000-0000-0000-0000-000000000003'
\set package1ID '00000000-0000-0000-0000-000000000001'
\set package2ID '00000000-0000-0000-0000-000000000002'
\set package3ID '00000000-0000-0000-0000-000000000003'
@ -37,10 +38,12 @@ select is(
insert into "user" (user_id, alias, email) values (:'user1ID', 'user1', 'user1@email.com');
insert into organization (organization_id, name, display_name, description, home_url)
values (:'org1ID', 'org1', 'Organization 1', 'Description 1', 'https://org1.com');
insert into chart_repository (chart_repository_id, name, display_name, url, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', :'user1ID');
insert into chart_repository (chart_repository_id, name, display_name, url, organization_id)
values (:'repo2ID', 'repo2', 'Repo 2', 'https://repo2.com', :'org1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, organization_id)
values (:'repo2ID', 'repo2', 'Repo 2', 'https://repo2.com', 0, :'org1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, organization_id)
values (:'repo3ID', 'repo3', 'Repo 3', 'https://repo3.com', 1, :'org1ID');
insert into package (
package_id,
name,
@ -48,8 +51,7 @@ insert into package (
logo_image_id,
stars,
tsdoc,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package1ID',
'package1',
@ -57,7 +59,6 @@ insert into package (
:'image1ID',
10,
generate_package_tsdoc('package1', null, 'description', '{"kw1", "kw2"}'),
0,
:'repo1ID'
);
insert into snapshot (
@ -113,8 +114,7 @@ insert into package (
logo_image_id,
stars,
tsdoc,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package2ID',
'package2',
@ -122,7 +122,6 @@ insert into package (
:'image2ID',
11,
generate_package_tsdoc('package2', null, 'description', '{"kw1", "kw2"}'),
0,
:'repo2ID'
);
insert into snapshot (
@ -181,16 +180,14 @@ insert into package (
latest_version,
logo_image_id,
tsdoc,
package_kind_id,
organization_id
repository_id
) values (
:'package3ID',
'package3',
'1.0.0',
:'image3ID',
generate_package_tsdoc('package3', null, 'description', '{"kw3"}'),
1,
:'org1ID'
:'repo3ID'
);
insert into snapshot (
package_id,
@ -220,7 +217,6 @@ select is(
"data": {
"packages": [{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "package1",
"normalized_name": "package1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -232,17 +228,17 @@ select is(
"deprecated": null,
"signed": null,
"created_at": 1592299234,
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1"
"display_name": "Repo 1",
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
}
}, {
"package_id": "00000000-0000-0000-0000-000000000002",
"kind": 0,
"name": "package2",
"normalized_name": "package2",
"logo_image_id": "00000000-0000-0000-0000-000000000002",
@ -254,17 +250,17 @@ select is(
"deprecated": true,
"signed": true,
"created_at": 1592299234,
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1",
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000002",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000002",
"kind": 0,
"name": "repo2",
"display_name": "Repo 2"
"display_name": "Repo 2",
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1"
}
}, {
"package_id": "00000000-0000-0000-0000-000000000003",
"kind": 1,
"name": "package3",
"normalized_name": "package3",
"logo_image_id": "00000000-0000-0000-0000-000000000003",
@ -276,10 +272,15 @@ select is(
"deprecated": null,
"signed": null,
"created_at": 1592299234,
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1",
"chart_repository": null
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000003",
"kind": 1,
"name": "repo3",
"display_name": "Repo 3",
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1"
}
}],
"facets": [{
"title": "Organization",
@ -310,7 +311,7 @@ select is(
"total": 1
}]
}, {
"title": "Chart Repository",
"title": "Repository",
"filter_key": "repo",
"options": [{
"id": "repo1",
@ -320,6 +321,10 @@ select is(
"id": "repo2",
"name": "Repo2",
"total": 1
}, {
"id": "repo3",
"name": "Repo3",
"total": 1
}]
}]
},
@ -341,7 +346,6 @@ select is(
"data": {
"packages": [{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "package1",
"normalized_name": "package1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -353,17 +357,17 @@ select is(
"deprecated": null,
"signed": null,
"created_at": 1592299234,
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1"
"display_name": "Repo 1",
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
}
}, {
"package_id": "00000000-0000-0000-0000-000000000002",
"kind": 0,
"name": "package2",
"normalized_name": "package2",
"logo_image_id": "00000000-0000-0000-0000-000000000002",
@ -375,13 +379,14 @@ select is(
"deprecated": true,
"signed": true,
"created_at": 1592299234,
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1",
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000002",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000002",
"kind": 0,
"name": "repo2",
"display_name": "Repo 2"
"display_name": "Repo 2",
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1"
}
}],
"facets": [{
@ -409,7 +414,7 @@ select is(
"total": 2
}]
}, {
"title": "Chart Repository",
"title": "Repository",
"filter_key": "repo",
"options": [{
"id": "repo1",
@ -439,7 +444,6 @@ select is(
"data": {
"packages": [{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "package1",
"normalized_name": "package1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -451,13 +455,14 @@ select is(
"deprecated": null,
"signed": null,
"created_at": 1592299234,
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1"
"display_name": "Repo 1",
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
}
}],
"facets": [{
@ -481,7 +486,7 @@ select is(
"total": 1
}]
}, {
"title": "Chart Repository",
"title": "Repository",
"filter_key": "repo",
"options": [{
"id": "repo1",
@ -519,7 +524,7 @@ select is(
-- Tests with kind and repositories filters
select is(
search_packages('{
"chart_repositories": [
"repositories": [
"repo1"
]
}')::jsonb,
@ -527,7 +532,6 @@ select is(
"data": {
"packages": [{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "package1",
"normalized_name": "package1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -539,13 +543,14 @@ select is(
"deprecated": null,
"signed": null,
"created_at": 1592299234,
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1"
"display_name": "Repo 1",
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
}
}],
"facets": null
@ -568,7 +573,6 @@ select is(
"data": {
"packages": [{
"package_id": "00000000-0000-0000-0000-000000000003",
"kind": 1,
"name": "package3",
"normalized_name": "package3",
"logo_image_id": "00000000-0000-0000-0000-000000000003",
@ -580,10 +584,15 @@ select is(
"deprecated": null,
"signed": null,
"created_at": 1592299234,
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1",
"chart_repository": null
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000003",
"kind": 1,
"name": "repo3",
"display_name": "Repo 3",
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1"
}
}],
"facets": null
},
@ -605,7 +614,6 @@ select is(
"data": {
"packages": [{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "package1",
"normalized_name": "package1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -617,13 +625,14 @@ select is(
"deprecated": null,
"signed": null,
"created_at": 1592299234,
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1"
"display_name": "Repo 1",
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
}
}],
"facets": null
@ -639,7 +648,7 @@ select is(
select is(
search_packages('{
"text": "",
"chart_repositories": [
"repositories": [
"repo1"
]
}')::jsonb,
@ -647,7 +656,6 @@ select is(
"data": {
"packages": [{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "package1",
"normalized_name": "package1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -659,13 +667,14 @@ select is(
"deprecated": null,
"signed": null,
"created_at": 1592299234,
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1"
"display_name": "Repo 1",
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
}
}],
"facets": null
@ -683,7 +692,7 @@ select is(
'{
"facets": true,
"text": "kw1",
"chart_repositories": [
"repositories": [
"repo2"
],
"deprecated": true
@ -692,7 +701,6 @@ select is(
"data": {
"packages": [{
"package_id": "00000000-0000-0000-0000-000000000002",
"kind": 0,
"name": "package2",
"normalized_name": "package2",
"logo_image_id": "00000000-0000-0000-0000-000000000002",
@ -704,13 +712,14 @@ select is(
"deprecated": true,
"signed": true,
"created_at": 1592299234,
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1",
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000002",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000002",
"kind": 0,
"name": "repo2",
"display_name": "Repo 2"
"display_name": "Repo 2",
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1"
}
}],
"facets": [{
@ -738,7 +747,7 @@ select is(
"total": 2
}]
}, {
"title": "Chart Repository",
"title": "Repository",
"filter_key": "repo",
"options": [{
"id": "repo1",
@ -764,7 +773,7 @@ select is(
'{
"facets": true,
"text": "kw1",
"chart_repositories": [
"repositories": [
"repo2"
],
"deprecated": false
@ -793,7 +802,7 @@ select is(
"total": 1
}]
}, {
"title": "Chart Repository",
"title": "Repository",
"filter_key": "repo",
"options": [{
"id": "repo1",
@ -815,7 +824,7 @@ select is(
'{
"facets": true,
"text": "kw1",
"chart_repositories": [
"repositories": [
"repo2"
]
}')::jsonb,
@ -843,7 +852,7 @@ select is(
"total": 1
}]
}, {
"title": "Chart Repository",
"title": "Repository",
"filter_key": "repo",
"options": [{
"id": "repo1",
@ -864,7 +873,7 @@ select is(
search_packages('{
"facets": true,
"text": "kw1",
"chart_repositories": [
"repositories": [
"repo3"
]
}')::jsonb,
@ -892,7 +901,7 @@ select is(
"total": 1
}]
}, {
"title": "Chart Repository",
"title": "Repository",
"filter_key": "repo",
"options": [{
"id": "repo1",
@ -913,7 +922,7 @@ select is(
search_packages('{
"facets": false,
"text": "kw1",
"package_kinds": [1, 2]
"repository_kinds": [1, 2]
}')::jsonb,
'{
"data": {
@ -941,7 +950,6 @@ select is(
"data": {
"packages": [{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "package1",
"normalized_name": "package1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -953,17 +961,17 @@ select is(
"deprecated": null,
"signed": null,
"created_at": 1592299234,
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1"
"display_name": "Repo 1",
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
}
}, {
"package_id": "00000000-0000-0000-0000-000000000002",
"kind": 0,
"name": "package2",
"normalized_name": "package2",
"logo_image_id": "00000000-0000-0000-0000-000000000002",
@ -975,13 +983,14 @@ select is(
"deprecated": true,
"signed": true,
"created_at": 1592299234,
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1",
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000002",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000002",
"kind": 0,
"name": "repo2",
"display_name": "Repo 2"
"display_name": "Repo 2",
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1"
}
}],
"facets": null
@ -1005,7 +1014,6 @@ select is(
"data": {
"packages": [{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "package1",
"normalized_name": "package1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -1017,13 +1025,14 @@ select is(
"deprecated": null,
"signed": null,
"created_at": 1592299234,
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1"
"display_name": "Repo 1",
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
}
}],
"facets": null
@ -1067,7 +1076,6 @@ select is(
"data": {
"packages": [{
"package_id": "00000000-0000-0000-0000-000000000002",
"kind": 0,
"name": "package2",
"normalized_name": "package2",
"logo_image_id": "00000000-0000-0000-0000-000000000002",
@ -1079,13 +1087,14 @@ select is(
"deprecated": true,
"signed": true,
"created_at": 1592299234,
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1",
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000002",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000002",
"kind": 0,
"name": "repo2",
"display_name": "Repo 2"
"display_name": "Repo 2",
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1"
}
}],
"facets": null
@ -1154,7 +1163,7 @@ select is(
"total": 2
}]
}, {
"title": "Chart Repository",
"title": "Repository",
"filter_key": "repo",
"options": [{
"id": "repo1",

View File

@ -9,19 +9,17 @@ select plan(6);
-- Seed some data
insert into "user" (user_id, alias, email) values (:'user1ID', 'user1', 'user1@email.com');
insert into chart_repository (chart_repository_id, name, display_name, url)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (
package_id,
name,
latest_version,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
0,
:'repo1ID'
);

View File

@ -11,19 +11,17 @@ select plan(10);
-- Seed some data
insert into "user" (user_id, alias, email) values (:'user1ID', 'user1', 'user1@email.com');
insert into chart_repository (chart_repository_id, name, display_name, url, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', :'user1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (
package_id,
name,
latest_version,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package1ID',
'package1',
'1.0.0',
0,
:'repo1ID'
);
insert into snapshot (package_id, version) values (:'package1ID', '1.0.0');
@ -41,8 +39,8 @@ select unregister_package('
"kind": 0,
"name": "package1",
"version": "1.0.0",
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001"
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001"
}
}
');
@ -60,8 +58,8 @@ select unregister_package('
"kind": 0,
"name": "package1",
"version": "0.0.9",
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001"
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001"
}
}
');
@ -79,8 +77,8 @@ select unregister_package('
"kind": 0,
"name": "package1",
"version": "0.0.9-rc1",
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001"
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001"
}
}
');
@ -98,8 +96,8 @@ select unregister_package('
"kind": 0,
"name": "package1",
"version": "0.0.9-rc2",
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001"
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001"
}
}
');

View File

@ -13,12 +13,13 @@ insert into organization (organization_id, name, display_name, description, home
values (:'org1ID', 'org1', 'Organization 1', 'Description 1', 'https://org1.com');
insert into user__organization (user_id, organization_id, confirmed) values(:'user1ID', :'org1ID', true);
-- Add chart repository owned by user
select add_chart_repository(:'user1ID', null, '
-- Add repository owned by user
select add_repository(:'user1ID', null, '
{
"name": "repo1",
"display_name": "Repository 1",
"url": "repo1_url"
"url": "repo1_url",
"kind": 0
}
'::jsonb);
select results_eq(
@ -27,9 +28,10 @@ select results_eq(
name,
display_name,
url,
repository_kind_id,
user_id,
organization_id
from chart_repository
from repository
where name = 'repo1'
$$,
$$
@ -37,19 +39,21 @@ select results_eq(
'repo1',
'Repository 1',
'repo1_url',
0,
'00000000-0000-0000-0000-000000000001'::uuid,
null::uuid
)
$$,
'Chart repository owned by user should exist'
'Repository owned by user should exist'
);
-- When an owning user and organization are provided, the organization takes precedence
select add_chart_repository(:'user1ID', 'org1', '
select add_repository(:'user1ID', 'org1', '
{
"name": "repo2",
"display_name": "Repository 2",
"url": "repo2_url"
"url": "repo2_url",
"kind": 0
}
'::jsonb);
select results_eq(
@ -58,9 +62,10 @@ select results_eq(
name,
display_name,
url,
repository_kind_id,
user_id,
organization_id
from chart_repository
from repository
where name = 'repo2'
$$,
$$
@ -68,21 +73,23 @@ select results_eq(
'repo2',
'Repository 2',
'repo2_url',
0,
null::uuid,
'00000000-0000-0000-0000-000000000001'::uuid
)
$$,
'Chart repository should exist and be owned by organization'
'Repository should exist and be owned by organization'
);
-- Add chart repository owned by organization, but user does not belong to it
-- Add repository owned by organization, but user does not belong to it
select throws_ok(
$$
select add_chart_repository('00000000-0000-0000-0000-000000000009', 'org1', '
select add_repository('00000000-0000-0000-0000-000000000009', 'org1', '
{
"name": "repo4",
"display_name": "Repository 4",
"url": "repo4_url"
"url": "repo4_url",
"kind": 1
}
'::jsonb)
$$,

View File

@ -15,51 +15,51 @@ values (:'user1ID', 'user1', 'user1@email.com');
insert into organization (organization_id, name, display_name, description, home_url)
values (:'org1ID', 'org1', 'Organization 1', 'Description 1', 'https://org1.com');
insert into user__organization (user_id, organization_id, confirmed) values(:'user1ID', :'org1ID', true);
insert into chart_repository (chart_repository_id, name, display_name, url, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', :'user1ID');
insert into chart_repository (chart_repository_id, name, display_name, url, organization_id)
values (:'repo2ID', 'repo2', 'Repo 2', 'https://repo2.com', :'org1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, organization_id)
values (:'repo2ID', 'repo2', 'Repo 2', 'https://repo2.com', 0, :'org1ID');
-- Try to delete a chart repository owned by a user by other user
-- Try to delete a repository owned by a user by other user
select throws_ok(
$$
select delete_chart_repository('00000000-0000-0000-0000-000000000002', 'repo1')
select delete_repository('00000000-0000-0000-0000-000000000002', 'repo1')
$$,
42501,
'insufficient_privilege',
'Chart repository delete should fail because requesting user is not the owner'
'Repository delete should fail because requesting user is not the owner'
);
-- Try to delete repository owned by organization by user not belonging to it
select throws_ok(
$$
select delete_chart_repository('00000000-0000-0000-0000-000000000002', 'repo2')
select delete_repository('00000000-0000-0000-0000-000000000002', 'repo2')
$$,
42501,
'insufficient_privilege',
'Chart repository delete should fail because requesting user does not belong to owning organization'
'Repository delete should fail because requesting user does not belong to owning organization'
);
-- Delete chart repository owned by user
select delete_chart_repository(:'user1ID', 'repo1');
-- Delete repository owned by user
select delete_repository(:'user1ID', 'repo1');
select is_empty(
$$
select name, display_name, url
from chart_repository
from repository
where name = 'repo1'
$$,
'Chart repository should have been deleted by user who owns it'
'Repository should have been deleted by user who owns it'
);
-- Delete chart repository owned by organization (requesting user belongs to organization)
select delete_chart_repository(:'user1ID', 'repo2');
-- Delete repository owned by organization (requesting user belongs to organization)
select delete_repository(:'user1ID', 'repo2');
select is_empty(
$$
select name, display_name, url
from chart_repository
from repository
where name = 'repo2'
$$,
'Chart repository should have been deleted by user who belongs to owning organization'
'Repository should have been deleted by user who belongs to owning organization'
);
-- Finish tests and rollback transaction

View File

@ -6,6 +6,9 @@ select plan(3);
\set user1ID '00000000-0000-0000-0000-000000000001'
\set user2ID '00000000-0000-0000-0000-000000000002'
\set org1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set repo2ID '00000000-0000-0000-0000-000000000002'
\set repo3ID '00000000-0000-0000-0000-000000000003'
-- Seed user and organization
insert into "user" (user_id, alias, email) values (:'user1ID', 'user1', 'user1@email.com');
@ -16,76 +19,86 @@ insert into user__organization (user_id, organization_id, confirmed) values(:'us
-- No repositories at this point
select is(
get_org_chart_repositories(:'user1ID', 'org1')::jsonb,
get_org_repositories(:'user1ID', 'org1')::jsonb,
'[]'::jsonb,
'With no repositories an empty json array is returned'
);
-- Seed some chart repositories
insert into chart_repository (
chart_repository_id,
-- Seed some repositories
insert into repository (
repository_id,
name,
display_name,
url,
last_tracking_ts,
last_tracking_errors,
repository_kind_id,
organization_id
) values (
'00000000-0000-0000-0000-000000000001',
:'repo1ID',
'repo1',
'Repo 1',
'https://repo1.com',
'1970-01-01 00:00:00 UTC',
'error1\nerror2\nerror3',
0,
:'org1ID'
);
insert into chart_repository (
chart_repository_id,
insert into repository (
repository_id,
name,
display_name,
url,
repository_kind_id,
organization_id
) values (
'00000000-0000-0000-0000-000000000002',
:'repo2ID',
'repo2',
'Repo 2',
'https://repo2.com',
0,
:'org1ID'
);
insert into chart_repository (
chart_repository_id,
insert into repository (
repository_id,
name,
display_name,
url
url,
repository_kind_id,
user_id
) values (
'00000000-0000-0000-0000-000000000003',
:'repo3ID',
'repo3',
'Repo 3',
'https://repo3.com'
'https://repo3.com',
1,
:'user1ID'
);
-- Run some tests
select is(
get_org_chart_repositories(:'user1ID', 'org1')::jsonb,
get_org_repositories(:'user1ID', 'org1')::jsonb,
'[{
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository_id": "00000000-0000-0000-0000-000000000001",
"name": "repo1",
"display_name": "Repo 1",
"url": "https://repo1.com",
"last_tracking_ts": 0,
"last_tracking_errors": "error1\\nerror2\\nerror3"
"last_tracking_errors": "error1\\nerror2\\nerror3",
"kind": 0
}, {
"chart_repository_id": "00000000-0000-0000-0000-000000000002",
"repository_id": "00000000-0000-0000-0000-000000000002",
"name": "repo2",
"display_name": "Repo 2",
"url": "https://repo2.com",
"last_tracking_ts": null,
"last_tracking_errors": null
"last_tracking_errors": null,
"kind": 0
}]'::jsonb,
'Repositories belonging to user provided are returned as a json array of objects'
);
select is(
get_org_chart_repositories(:'user2ID', 'org1')::jsonb,
get_org_repositories(:'user2ID', 'org1')::jsonb,
'[]'::jsonb,
'No repositories are returned as user provided does not belong to the organization'
);

View File

@ -0,0 +1,58 @@
-- Start transaction and plan tests
begin;
select plan(3);
-- Declare some variables
\set user1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set repo2ID '00000000-0000-0000-0000-000000000002'
\set repo3ID '00000000-0000-0000-0000-000000000003'
-- No repositories at this point
select is(
get_repositories_by_kind(0)::jsonb,
'[]'::jsonb,
'With no repositories an empty json array is returned'
);
-- Seed some data
insert into "user" (user_id, alias, email)
values (:'user1ID', 'user1', 'user1@email.com');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo2ID', 'repo2', 'Repo 2', 'https://repo2.com', 0, :'user1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo3ID', 'repo3', 'Repo 3', 'https://repo3.com', 1, :'user1ID');
-- Run some tests
select is(
get_repositories_by_kind(0)::jsonb,
'[{
"repository_id": "00000000-0000-0000-0000-000000000001",
"name": "repo1",
"display_name": "Repo 1",
"url": "https://repo1.com"
}, {
"repository_id": "00000000-0000-0000-0000-000000000002",
"name": "repo2",
"display_name": "Repo 2",
"url": "https://repo2.com"
}]'::jsonb,
'Repositories 1 and 2 are returned'
);
select is(
get_repositories_by_kind(1)::jsonb,
'[{
"repository_id": "00000000-0000-0000-0000-000000000003",
"name": "repo3",
"display_name": "Repo 3",
"url": "https://repo3.com"
}]'::jsonb,
'Repository 3 is returned'
);
-- Finish tests and rollback transaction
select * from finish();
rollback;

View File

@ -0,0 +1,36 @@
-- Start transaction and plan tests
begin;
select plan(2);
-- Declare some variables
\set user1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
-- Non existing repository
select is_empty(
$$ select get_repository_by_name('repo1') $$,
'If repository requested does not exist no rows are returned'
);
-- Seed some data
insert into "user" (user_id, alias, email)
values (:'user1ID', 'user1', 'user1@email.com');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
-- One repository has just been seeded
select is(
get_repository_by_name('repo1')::jsonb,
'{
"repository_id": "00000000-0000-0000-0000-000000000001",
"name": "repo1",
"display_name": "Repo 1",
"url": "https://repo1.com",
"kind": 0
}'::jsonb,
'Repository just seeded is returned as a json object'
);
-- Finish tests and rollback transaction
select * from finish();
rollback;

View File

@ -3,6 +3,7 @@ begin;
select plan(2);
-- Declare some variables
\set user1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set package1ID '00000000-0000-0000-0000-000000000001'
\set package2ID '00000000-0000-0000-0000-000000000002'
@ -11,25 +12,25 @@ select plan(2);
-- No packages at this point
select is(
get_chart_repository_packages_digest(:'repo1ID'::uuid)::jsonb,
get_repository_packages_digest(:'repo1ID'::uuid)::jsonb,
'{}'::jsonb,
'With no repositories/packages an empty json object is returned'
);
-- Seed some packages
insert into chart_repository (chart_repository_id, name, display_name, url)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com');
-- Seed some data
insert into "user" (user_id, alias, email)
values (:'user1ID', 'user1', 'user1@email.com');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (
package_id,
name,
latest_version,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package1ID',
'package1',
'1.0.0',
0,
:'repo1ID'
);
insert into snapshot (
@ -54,13 +55,11 @@ insert into package (
package_id,
name,
latest_version,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package2ID',
'package2',
'1.0.0',
0,
:'repo1ID'
);
insert into snapshot (
@ -84,7 +83,7 @@ insert into snapshot (
-- Some packages have just been seeded
select is(
get_chart_repository_packages_digest(:'repo1ID'::uuid)::jsonb,
get_repository_packages_digest(:'repo1ID'::uuid)::jsonb,
'{
"package1@1.0.0": "digest-package1-1.0.0",
"package1@0.0.9": "digest-package1-0.0.9",

View File

@ -4,26 +4,30 @@ select plan(3);
-- Declare some variables
\set user1ID '00000000-0000-0000-0000-000000000001'
\set org1ID '00000000-0000-0000-0000-000000000001'
-- Seed user
-- Seed some data
insert into "user" (user_id, alias, email)
values (:'user1ID', 'user1', 'user1@email.com');
insert into organization (organization_id, name, display_name, description, home_url)
values (:'org1ID', 'org1', 'Organization 1', 'Description 1', 'https://org1.com');
-- No repositories at this point
select is(
get_user_chart_repositories(:'user1ID')::jsonb,
get_user_repositories(:'user1ID')::jsonb,
'[]'::jsonb,
'With no repositories an empty json array is returned'
);
-- Seed some chart repositories
insert into chart_repository (
chart_repository_id,
insert into repository (
repository_id,
name,
display_name,
url,
last_tracking_ts,
last_tracking_errors,
repository_kind_id,
user_id
) values (
'00000000-0000-0000-0000-000000000001',
@ -32,55 +36,64 @@ insert into chart_repository (
'https://repo1.com',
'1970-01-01 00:00:00 UTC',
'error1\nerror2\nerror3',
0,
:'user1ID'
);
insert into chart_repository (
chart_repository_id,
insert into repository (
repository_id,
name,
display_name,
url,
repository_kind_id,
user_id
) values (
'00000000-0000-0000-0000-000000000002',
'repo2',
'Repo 2',
'https://repo2.com',
0,
:'user1ID'
);
insert into chart_repository (
chart_repository_id,
insert into repository (
repository_id,
name,
display_name,
url
url,
repository_kind_id,
organization_id
) values (
'00000000-0000-0000-0000-000000000003',
'repo3',
'Repo 3',
'https://repo3.com'
'https://repo3.com',
0,
:'org1ID'
);
-- Run some tests
select is(
get_user_chart_repositories(:'user1ID')::jsonb,
get_user_repositories(:'user1ID')::jsonb,
'[{
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository_id": "00000000-0000-0000-0000-000000000001",
"name": "repo1",
"display_name": "Repo 1",
"url": "https://repo1.com",
"last_tracking_ts": 0,
"last_tracking_errors": "error1\\nerror2\\nerror3"
"last_tracking_errors": "error1\\nerror2\\nerror3",
"kind": 0
}, {
"chart_repository_id": "00000000-0000-0000-0000-000000000002",
"repository_id": "00000000-0000-0000-0000-000000000002",
"name": "repo2",
"display_name": "Repo 2",
"url": "https://repo2.com",
"last_tracking_ts": null,
"last_tracking_errors": null
"last_tracking_errors": null,
"kind": 0
}]'::jsonb,
'Repositories belonging to user provided are returned as a json array of objects'
);
select is(
get_user_chart_repositories(null)::jsonb,
get_user_repositories(null)::jsonb,
'[]'::jsonb,
'Repositories not belonging to any user are not returned'
);

View File

@ -24,15 +24,15 @@ insert into organization (organization_id, name, display_name, description, home
values (:'org3ID', 'org3', 'Organization 3', 'Description 3', 'https://org3.com');
insert into user__organization (user_id, organization_id, confirmed) values(:'user1ID', :'org1ID', true);
insert into user__organization (user_id, organization_id, confirmed) values(:'user1ID', :'org3ID', true);
insert into chart_repository (chart_repository_id, name, display_name, url, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', :'user1ID');
insert into chart_repository (chart_repository_id, name, display_name, url, organization_id)
values (:'repo2ID', 'repo2', 'Repo 2', 'https://repo2.com', :'org1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, organization_id)
values (:'repo2ID', 'repo2', 'Repo 2', 'https://repo2.com', 0, :'org1ID');
-- Try to transfer repository owned by a user to other user
select throws_ok(
$$
select transfer_chart_repository(
select transfer_repository(
'repo1',
'00000000-0000-0000-0000-000000000002',
null
@ -40,13 +40,13 @@ select throws_ok(
$$,
42501,
'insufficient_privilege',
'Chart repository transfer should fail because requesting user is not the owner'
'Repository transfer should fail because requesting user is not the owner'
);
-- Try to transfer repository owned by organization to user not belonging to it
select throws_ok(
$$
select transfer_chart_repository(
select transfer_repository(
'repo2',
'00000000-0000-0000-0000-000000000002',
null
@ -54,14 +54,14 @@ select throws_ok(
$$,
42501,
'insufficient_privilege',
'Chart repository transfer should fail because requesting user does not belong to owning organization'
'Repository transfer should fail because requesting user does not belong to owning organization'
);
-- Try to transfer repository owned by a user to an organization the user does
-- not belong to
select throws_ok(
$$
select transfer_chart_repository(
select transfer_repository(
'repo1',
'00000000-0000-0000-0000-000000000001',
'org2'
@ -69,11 +69,11 @@ select throws_ok(
$$,
42501,
'insufficient_privilege',
'Chart repository transfer should fail because requesting user does not belong to dst org'
'Repository transfer should fail because requesting user does not belong to dst org'
);
-- Transfer org owned chart repository to user
select transfer_chart_repository(
-- Transfer org owned repository to user
select transfer_repository(
'repo2',
'00000000-0000-0000-0000-000000000001',
null
@ -81,22 +81,22 @@ select transfer_chart_repository(
select results_eq(
$$
select user_id, organization_id
from chart_repository
from repository
where name = 'repo2'
$$,
$$
values ('00000000-0000-0000-0000-000000000001'::uuid, null::uuid)
$$,
'Chart repository should have been transferred to user1'
'Repository should have been transferred to user1'
);
select transfer_chart_repository(
select transfer_repository(
'repo2',
'00000000-0000-0000-0000-000000000001',
'org1'
);
-- Transfer org owned chart repository to other org
select transfer_chart_repository(
-- Transfer org owned repository to other org
select transfer_repository(
'repo2',
'00000000-0000-0000-0000-000000000001',
'org3'
@ -104,17 +104,17 @@ select transfer_chart_repository(
select results_eq(
$$
select user_id, organization_id
from chart_repository
from repository
where name = 'repo2'
$$,
$$
values (null::uuid, '00000000-0000-0000-0000-000000000003'::uuid)
$$,
'Chart repository should have been transferred to org3'
'Repository should have been transferred to org3'
);
-- Transfer user owned chart repository to org
select transfer_chart_repository(
-- Transfer user owned repository to org
select transfer_repository(
'repo1',
'00000000-0000-0000-0000-000000000001',
'org1'
@ -122,13 +122,13 @@ select transfer_chart_repository(
select results_eq(
$$
select user_id, organization_id
from chart_repository
from repository
where name = 'repo1'
$$,
$$
values (null::uuid, '00000000-0000-0000-0000-000000000001'::uuid)
$$,
'Chart repository should have been transferred to org1'
'Repository should have been transferred to org1'
);
-- Finish tests and rollback transaction

View File

@ -15,15 +15,15 @@ values (:'user1ID', 'user1', 'user1@email.com');
insert into organization (organization_id, name, display_name, description, home_url)
values (:'org1ID', 'org1', 'Organization 1', 'Description 1', 'https://org1.com');
insert into user__organization (user_id, organization_id, confirmed) values(:'user1ID', :'org1ID', true);
insert into chart_repository (chart_repository_id, name, display_name, url, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', :'user1ID');
insert into chart_repository (chart_repository_id, name, display_name, url, organization_id)
values (:'repo2ID', 'repo2', 'Repo 2', 'https://repo2.com', :'org1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, organization_id)
values (:'repo2ID', 'repo2', 'Repo 2', 'https://repo2.com', 0, :'org1ID');
-- Try to update repository owned by a user by other user
select throws_ok(
$$
select update_chart_repository('00000000-0000-0000-0000-000000000002', '
select update_repository('00000000-0000-0000-0000-000000000002', '
{
"name": "repo1",
"display_name": "Repo 1 updated",
@ -33,13 +33,13 @@ select throws_ok(
$$,
42501,
'insufficient_privilege',
'Chart repository update should fail because requesting user is not the owner'
'Repository update should fail because requesting user is not the owner'
);
-- Try to update repository owned by organization by user not belonging to it
select throws_ok(
$$
select update_chart_repository('00000000-0000-0000-0000-000000000002', '
select update_repository('00000000-0000-0000-0000-000000000002', '
{
"name": "repo2",
"display_name": "Repo 2 updated",
@ -49,11 +49,11 @@ select throws_ok(
$$,
42501,
'insufficient_privilege',
'Chart repository update should fail because requesting user does not belong to owning organization'
'Repository update should fail because requesting user does not belong to owning organization'
);
-- Update chart repository owned by user
select update_chart_repository(:'user1ID', '
-- Update repository owned by user
select update_repository(:'user1ID', '
{
"name": "repo1",
"display_name": "Repo 1 updated",
@ -63,17 +63,17 @@ select update_chart_repository(:'user1ID', '
select results_eq(
$$
select name, display_name, url
from chart_repository
from repository
where name = 'repo1'
$$,
$$
values ('repo1', 'Repo 1 updated', 'https://repo1.com/updated')
$$,
'Chart repository should have been updated by user who owns it'
'Repository should have been updated by user who owns it'
);
-- Update chart repository owned by organization (requesting user belongs to organization)
select update_chart_repository(:'user1ID', '
-- Update repository owned by organization (requesting user belongs to organization)
select update_repository(:'user1ID', '
{
"name": "repo2",
"display_name": "Repo 2 updated",
@ -83,13 +83,13 @@ select update_chart_repository(:'user1ID', '
select results_eq(
$$
select name, display_name, url
from chart_repository
from repository
where name = 'repo2'
$$,
$$
values ('repo2', 'Repo 2 updated', 'https://repo2.com/updated')
$$,
'Chart repository should have been updated by user who belongs to owning organization'
'Repository should have been updated by user who belongs to owning organization'
);
-- Finish tests and rollback transaction

View File

@ -4,22 +4,15 @@ select plan(1);
-- Declare some variables
\set user1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set package1ID '00000000-0000-0000-0000-000000000001'
-- Seed some data
insert into "user" (user_id, alias, email)
values (:'user1ID', 'user1', 'user1@email.com');
insert into package (
package_id,
name,
latest_version,
package_kind_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
1
);
insert into "user" (user_id, alias, email) values (:'user1ID', 'user1', 'user1@email.com');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (package_id, name, latest_version, repository_id)
values (:'package1ID', 'Package 1', '1.0.0', :'repo1ID');
-- Add subscription
select add_subscription('

View File

@ -4,22 +4,15 @@ select plan(1);
-- Declare some variables
\set user1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set package1ID '00000000-0000-0000-0000-000000000001'
-- Seed some data
insert into "user" (user_id, alias, email)
values (:'user1ID', 'user1', 'user1@email.com');
insert into package (
package_id,
name,
latest_version,
package_kind_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
1
);
insert into "user" (user_id, alias, email) values (:'user1ID', 'user1', 'user1@email.com');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (package_id, name, latest_version, repository_id)
values (:'package1ID', 'Package 1', '1.0.0', :'repo1ID');
insert into subscription (user_id, package_id, event_kind_id)
values (:'user1ID', :'package1ID', 0);

View File

@ -5,6 +5,7 @@ select plan(3);
-- Declare some variables
\set user1ID '00000000-0000-0000-0000-000000000001'
\set user2ID '00000000-0000-0000-0000-000000000002'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set package1ID '00000000-0000-0000-0000-000000000001'
\set package2ID '00000000-0000-0000-0000-000000000002'
@ -13,17 +14,10 @@ insert into "user" (user_id, alias, email)
values (:'user1ID', 'user1', 'user1@email.com');
insert into "user" (user_id, alias, email)
values (:'user2ID', 'user2', 'user2@email.com');
insert into package (
package_id,
name,
latest_version,
package_kind_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
1
);
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (package_id, name, latest_version, repository_id)
values (:'package1ID', 'Package 1', '1.0.0', :'repo1ID');
insert into subscription (user_id, package_id, event_kind_id)
values (:'user1ID', :'package1ID', 0);

View File

@ -6,6 +6,7 @@ select plan(2);
\set user1ID '00000000-0000-0000-0000-000000000001'
\set user2ID '00000000-0000-0000-0000-000000000002'
\set user3ID '00000000-0000-0000-0000-000000000003'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set package1ID '00000000-0000-0000-0000-000000000001'
\set package2ID '00000000-0000-0000-0000-000000000002'
@ -16,17 +17,10 @@ insert into "user" (user_id, alias, email)
values (:'user2ID', 'user2', 'user2@email.com');
insert into "user" (user_id, alias, email)
values (:'user3ID', 'user3', 'user3@email.com');
insert into package (
package_id,
name,
latest_version,
package_kind_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
1
);
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (package_id, name, latest_version, repository_id)
values (:'package1ID', 'Package 1', '1.0.0', :'repo1ID');
insert into subscription (user_id, package_id, event_kind_id)
values (:'user1ID', :'package1ID', 0);
insert into subscription (user_id, package_id, event_kind_id)

View File

@ -7,6 +7,7 @@ select plan(2);
\set user1ID '00000000-0000-0000-0000-000000000001'
\set user2ID '00000000-0000-0000-0000-000000000002'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set repo2ID '00000000-0000-0000-0000-000000000002'
\set package1ID '00000000-0000-0000-0000-000000000001'
\set package2ID '00000000-0000-0000-0000-000000000002'
\set image1ID '00000000-0000-0000-0000-000000000001'
@ -19,38 +20,14 @@ insert into "user" (user_id, alias, email)
values (:'user1ID', 'user1', 'user1@email.com');
insert into "user" (user_id, alias, email)
values (:'user2ID', 'user2', 'user2@email.com');
insert into chart_repository (chart_repository_id, name, display_name, url, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', :'user1ID');
insert into package (
package_id,
name,
latest_version,
logo_image_id,
package_kind_id,
chart_repository_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
:'image1ID',
0,
:'repo1ID'
);
insert into package (
package_id,
name,
latest_version,
logo_image_id,
package_kind_id,
organization_id
) values (
:'package2ID',
'Package 2',
'1.0.0',
:'image2ID',
1,
:'org1ID'
);
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, organization_id)
values (:'repo2ID', 'repo2', 'Repo 2', 'https://repo2.com', 0, :'org1ID');
insert into package (package_id, name, latest_version, logo_image_id, repository_id)
values (:'package1ID', 'Package 1', '1.0.0', :'image1ID', :'repo1ID');
insert into package (package_id, name, latest_version, logo_image_id, repository_id)
values (:'package2ID', 'Package 2', '1.0.0', :'image2ID', :'repo2ID');
insert into subscription (user_id, package_id, event_kind_id)
values (:'user1ID', :'package1ID', 0);
insert into subscription (user_id, package_id, event_kind_id)
@ -63,28 +40,31 @@ select is(
get_user_subscriptions(:'user1ID')::jsonb,
'[{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "Package 1",
"normalized_name": "package-1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"repository": {
"kind": 0,
"name": "repo1",
"display_name": "Repo 1"
"display_name": "Repo 1",
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
},
"event_kinds": [0, 1]
}, {
"package_id": "00000000-0000-0000-0000-000000000002",
"kind": 1,
"name": "Package 2",
"normalized_name": "package-2",
"logo_image_id": "00000000-0000-0000-0000-000000000002",
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1",
"chart_repository": null,
"repository": {
"kind": 0,
"name": "repo2",
"display_name": "Repo 2",
"user_alias": null,
"organization_name": "org1",
"organization_display_name": "Organization 1"
},
"event_kinds": [0]
}]'::jsonb,
'Two subscriptions should be returned'

View File

@ -5,6 +5,7 @@ select plan(5);
-- Declare some variables
\set user1ID '00000000-0000-0000-0000-000000000001'
\set org1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set package1ID '00000000-0000-0000-0000-000000000001'
-- Seed some data
@ -13,17 +14,10 @@ values (:'user1ID', 'user1', 'user1@email.com');
insert into organization (organization_id, name, display_name, description, home_url)
values (:'org1ID', 'org1', 'Organization 1', 'Description 1', 'https://org1.com');
insert into user__organization (user_id, organization_id, confirmed) values(:'user1ID', :'org1ID', true);
insert into package (
package_id,
name,
latest_version,
package_kind_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
1
);
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (package_id, name, latest_version, repository_id)
values (:'package1ID', 'Package 1', '1.0.0', :'repo1ID');
-- Add webhook owned by user
select add_webhook(:'user1ID', null, '

View File

@ -16,21 +16,19 @@ values (:'user1ID', 'user1', 'user1@email.com');
insert into organization (organization_id, name, display_name, description, home_url)
values (:'org1ID', 'org1', 'Organization 1', 'Description 1', 'https://org1.com');
insert into user__organization (user_id, organization_id, confirmed) values(:'user1ID', :'org1ID', true);
insert into chart_repository (chart_repository_id, name, display_name, url, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', :'user1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (
package_id,
name,
latest_version,
logo_image_id,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
:'image1ID',
0,
:'repo1ID'
);
insert into snapshot (
@ -83,7 +81,6 @@ select is(
"packages": [
{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "Package 1",
"normalized_name": "package-1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -95,13 +92,14 @@ select is(
"deprecated": null,
"signed": null,
"created_at": 1592299234,
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1"
"display_name": "Repo 1",
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
}
}
],

View File

@ -12,21 +12,19 @@ select plan(2);
-- Seed some data
insert into "user" (user_id, alias, email)
values (:'user1ID', 'user1', 'user1@email.com');
insert into chart_repository (chart_repository_id, name, display_name, url, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', :'user1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (
package_id,
name,
latest_version,
logo_image_id,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
:'image1ID',
0,
:'repo1ID'
);
insert into snapshot (
@ -79,7 +77,6 @@ select is(
"packages": [
{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "Package 1",
"normalized_name": "package-1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -91,13 +88,14 @@ select is(
"deprecated": null,
"signed": null,
"created_at": 1592299234,
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1"
"display_name": "Repo 1",
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
}
}
],

View File

@ -16,21 +16,19 @@ select plan(2);
-- Seed some data
insert into "user" (user_id, alias, email)
values (:'user1ID', 'user1', 'user1@email.com');
insert into chart_repository (chart_repository_id, name, display_name, url, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', :'user1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (
package_id,
name,
latest_version,
logo_image_id,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
:'image1ID',
0,
:'repo1ID'
);
insert into snapshot (
@ -136,7 +134,6 @@ select is(
"packages": [
{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "Package 1",
"normalized_name": "package-1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -148,13 +145,14 @@ select is(
"deprecated": null,
"signed": null,
"created_at": 1592299234,
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1"
"display_name": "Repo 1",
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
}
}
],

View File

@ -14,21 +14,19 @@ select plan(3);
-- Seed some data
insert into "user" (user_id, alias, email)
values (:'user1ID', 'user1', 'user1@email.com');
insert into chart_repository (chart_repository_id, name, display_name, url, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', :'user1ID');
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (
package_id,
name,
latest_version,
logo_image_id,
package_kind_id,
chart_repository_id
repository_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
:'image1ID',
0,
:'repo1ID'
);
insert into snapshot (
@ -96,7 +94,6 @@ select is(
"packages": [
{
"package_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "Package 1",
"normalized_name": "package-1",
"logo_image_id": "00000000-0000-0000-0000-000000000001",
@ -108,13 +105,14 @@ select is(
"deprecated": null,
"signed": null,
"created_at": 1592299234,
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null,
"chart_repository": {
"chart_repository_id": "00000000-0000-0000-0000-000000000001",
"repository": {
"repository_id": "00000000-0000-0000-0000-000000000001",
"kind": 0,
"name": "repo1",
"display_name": "Repo 1"
"display_name": "Repo 1",
"user_alias": "user1",
"organization_name": null,
"organization_display_name": null
}
}
],

View File

@ -6,6 +6,7 @@ select plan(6);
\set user1ID '00000000-0000-0000-0000-000000000001'
\set user2ID '00000000-0000-0000-0000-000000000002'
\set org1ID '00000000-0000-0000-0000-000000000001'
\set repo1ID '00000000-0000-0000-0000-000000000001'
\set package1ID '00000000-0000-0000-0000-000000000001'
\set package2ID '00000000-0000-0000-0000-000000000002'
\set webhook1ID '00000000-0000-0000-0000-000000000001'
@ -17,28 +18,12 @@ values (:'user1ID', 'user1', 'user1@email.com');
insert into organization (organization_id, name, display_name, description, home_url)
values (:'org1ID', 'org1', 'Organization 1', 'Description 1', 'https://org1.com');
insert into user__organization (user_id, organization_id, confirmed) values(:'user1ID', :'org1ID', true);
insert into package (
package_id,
name,
latest_version,
package_kind_id
) values (
:'package1ID',
'Package 1',
'1.0.0',
1
);
insert into package (
package_id,
name,
latest_version,
package_kind_id
) values (
:'package2ID',
'Package 2',
'1.0.0',
1
);
insert into repository (repository_id, name, display_name, url, repository_kind_id, user_id)
values (:'repo1ID', 'repo1', 'Repo 1', 'https://repo1.com', 0, :'user1ID');
insert into package (package_id, name, latest_version, repository_id)
values (:'package1ID', 'Package 1', '1.0.0', :'repo1ID');
insert into package (package_id, name, latest_version, repository_id)
values (:'package2ID', 'Package 2', '1.0.0', :'repo1ID');
insert into webhook (webhook_id, name, url, user_id)
values (:'webhook1ID', 'webhook1', 'http://webhook1.url', :'user1ID');
insert into webhook__event_kind (webhook_id, event_kind_id) values (:'webhook1ID', 0);

View File

@ -15,7 +15,6 @@ select has_extension('pgcrypto');
-- Check expected tables exist
select tables_are(array[
'api_key',
'chart_repository',
'email_verification_code',
'event',
'event_kind',
@ -26,7 +25,8 @@ select tables_are(array[
'organization',
'package',
'package__maintainer',
'package_kind',
'repository',
'repository_kind',
'session',
'snapshot',
'subscription',
@ -48,16 +48,6 @@ select columns_are('api_key', array[
'user_id',
'created_at'
]);
select columns_are('chart_repository', array[
'chart_repository_id',
'name',
'display_name',
'url',
'last_tracking_ts',
'last_tracking_errors',
'user_id',
'organization_id'
]);
select columns_are('email_verification_code', array[
'email_verification_code_id',
'user_id',
@ -118,17 +108,25 @@ select columns_are('package', array[
'logo_image_id',
'stars',
'tsdoc',
'package_kind_id',
'user_id',
'organization_id',
'chart_repository_id'
'repository_id'
]);
select columns_are('package__maintainer', array[
'package_id',
'maintainer_id'
]);
select columns_are('package_kind', array[
'package_kind_id',
select columns_are('repository', array[
'repository_id',
'name',
'display_name',
'url',
'last_tracking_ts',
'last_tracking_errors',
'repository_kind_id',
'user_id',
'organization_id'
]);
select columns_are('repository_kind', array[
'repository_kind_id',
'name'
]);
select columns_are('session', array[
@ -215,13 +213,6 @@ select indexes_are('api_key', array[
'api_key_pkey',
'api_key_user_id_idx'
]);
select indexes_are('chart_repository', array[
'chart_repository_pkey',
'chart_repository_name_key',
'chart_repository_url_key',
'chart_repository_user_id_idx',
'chart_repository_organization_id_idx'
]);
select indexes_are('email_verification_code', array[
'email_verification_code_pkey',
'email_verification_code_user_id_key'
@ -255,19 +246,23 @@ select indexes_are('organization', array[
]);
select indexes_are('package', array[
'package_pkey',
'package_chart_repository_id_idx',
'package_package_kind_id_idx',
'package_tsdoc_idx',
'package_stars_idx',
'package_user_id_idx',
'package_organization_id_idx',
'package_unique_name_idx'
'package_repository_id_idx',
'package_repository_id_name_key'
]);
select indexes_are('package__maintainer', array[
'package__maintainer_pkey'
]);
select indexes_are('package_kind', array[
'package_kind_pkey'
select indexes_are('repository', array[
'repository_pkey',
'repository_name_key',
'repository_url_key',
'repository_repository_kind_id_idx',
'repository_user_id_idx',
'repository_organization_id_idx'
]);
select indexes_are('repository_kind', array[
'repository_kind_pkey'
]);
select indexes_are('session', array[
'session_pkey'
@ -309,6 +304,15 @@ select has_function('get_api_key');
select has_function('get_user_api_keys');
select has_function('update_api_key');
select has_function('get_pending_event');
select has_function('get_image');
select has_function('register_image');
select has_function('add_notification');
select has_function('get_pending_notification');
select has_function('update_notification_status');
select has_function('add_organization');
select has_function('add_organization_member');
select has_function('confirm_organization_membership');
@ -319,13 +323,6 @@ select has_function('get_user_organizations');
select has_function('update_organization');
select has_function('user_belongs_to_organization');
select has_function('get_user_profile');
select has_function('register_session');
select has_function('register_user');
select has_function('update_user_password');
select has_function('update_user_profile');
select has_function('verify_email');
select has_function('generate_package_tsdoc');
select has_function('get_package');
select has_function('get_package_summary');
@ -340,18 +337,15 @@ select has_function('semver_gte');
select has_function('toggle_star');
select has_function('unregister_package');
select has_function('add_chart_repository');
select has_function('delete_chart_repository');
select has_function('get_chart_repositories');
select has_function('get_chart_repository_by_name');
select has_function('get_chart_repository_packages_digest');
select has_function('get_org_chart_repositories');
select has_function('get_user_chart_repositories');
select has_function('transfer_chart_repository');
select has_function('update_chart_repository');
select has_function('get_image');
select has_function('register_image');
select has_function('add_repository');
select has_function('delete_repository');
select has_function('get_repositories_by_kind');
select has_function('get_repository_by_name');
select has_function('get_repository_packages_digest');
select has_function('get_org_repositories');
select has_function('get_user_repositories');
select has_function('transfer_repository');
select has_function('update_repository');
select has_function('add_subscription');
select has_function('delete_subscription');
@ -359,11 +353,12 @@ select has_function('get_package_subscriptions');
select has_function('get_subscriptors');
select has_function('get_user_subscriptions');
select has_function('get_pending_event');
select has_function('add_notification');
select has_function('get_pending_notification');
select has_function('update_notification_status');
select has_function('get_user_profile');
select has_function('register_session');
select has_function('register_user');
select has_function('update_user_password');
select has_function('update_user_profile');
select has_function('verify_email');
select has_function('add_webhook');
select has_function('delete_webhook');
@ -374,15 +369,16 @@ select has_function('get_webhooks_subscribed_to');
select has_function('update_webhook');
select has_function('user_has_access_to_webhook');
-- Check package kinds exist
-- Check repository kinds exist
select results_eq(
'select * from package_kind',
'select * from repository_kind',
$$ values
(0, 'Helm charts'),
(1, 'Falco rules'),
(2, 'OPA policies')
(2, 'OPA policies'),
(3, 'OLM operators')
$$,
'Package kinds should exist'
'Repository kinds should exist'
);
-- Check event kinds exist

View File

@ -15,7 +15,7 @@ tags:
description: ""
- name: Organizations
description: ""
- name: Chart repositories
- name: Repositories
description: ""
- name: Packages
description: ""
@ -365,14 +365,14 @@ paths:
$ref: "#/components/responses/TooManyRequests"
"500":
$ref: "#/components/responses/InternalServerError"
/chart-repositories/user:
/repositories/user:
get:
tags:
- Chart repositories
- Repositories
security:
- ApiKeyAuth: []
- CookieAuth: []
summary: Get user's chart repositories
summary: Get user's repositories
responses:
"200":
description: ""
@ -381,7 +381,7 @@ paths:
schema:
type: array
items:
$ref: "#/components/schemas/ChartRepository"
$ref: "#/components/schemas/Repository"
"401":
$ref: "#/components/responses/UnauthorizedError"
"429":
@ -390,17 +390,17 @@ paths:
$ref: "#/components/responses/InternalServerError"
post:
tags:
- Chart repositories
- Repositories
security:
- ApiKeyAuth: []
- CookieAuth: []
summary: Add user's chart repository
summary: Add user's repository
requestBody:
description: ""
content:
application/json:
schema:
$ref: "#/components/schemas/ChartRepositorySummary"
$ref: "#/components/schemas/RepositorySummary"
responses:
"201":
$ref: "#/components/responses/Created"
@ -412,14 +412,14 @@ paths:
$ref: "#/components/responses/TooManyRequests"
"500":
$ref: "#/components/responses/InternalServerError"
"/chart-repositories/user/{repoName}":
"/repositories/user/{repoName}":
put:
tags:
- Chart repositories
- Repositories
security:
- ApiKeyAuth: []
- CookieAuth: []
summary: Update user's chart repository
summary: Update user's repository
parameters:
- $ref: "#/components/parameters/RepoNameParam"
requestBody:
@ -427,7 +427,7 @@ paths:
content:
application/json:
schema:
$ref: "#/components/schemas/ChartRepositorySummary"
$ref: "#/components/schemas/RepositorySummary"
responses:
"204":
$ref: "#/components/responses/NoContent"
@ -443,11 +443,11 @@ paths:
$ref: "#/components/responses/InternalServerError"
delete:
tags:
- Chart repositories
- Repositories
security:
- ApiKeyAuth: []
- CookieAuth: []
summary: Delete user's chart repository
summary: Delete user's repository
parameters:
- $ref: "#/components/parameters/RepoNameParam"
responses:
@ -461,14 +461,14 @@ paths:
$ref: "#/components/responses/TooManyRequests"
"500":
$ref: "#/components/responses/InternalServerError"
"/chart-repositories/user/{repoName}/transfer":
"/repositories/user/{repoName}/transfer":
put:
tags:
- Chart repositories
- Repositories
security:
- ApiKeyAuth: []
- CookieAuth: []
summary: Transfer user's chart repository ownership to an organization
summary: Transfer user's repository ownership to an organization
parameters:
- $ref: "#/components/parameters/RepoNameParam"
- $ref: "#/components/parameters/OrgNameToTransferParam"
@ -483,14 +483,14 @@ paths:
$ref: "#/components/responses/TooManyRequests"
"500":
$ref: "#/components/responses/InternalServerError"
"/chart-repositories/org/{orgName}":
"/repositories/org/{orgName}":
get:
tags:
- Chart repositories
- Repositories
security:
- ApiKeyAuth: []
- CookieAuth: []
summary: Get organization's chart repositories
summary: Get organization's Repositories
parameters:
- $ref: "#/components/parameters/OrgNameParam"
responses:
@ -501,7 +501,7 @@ paths:
schema:
type: array
items:
$ref: "#/components/schemas/ChartRepository"
$ref: "#/components/schemas/Repository"
"401":
$ref: "#/components/responses/UnauthorizedError"
"429":
@ -510,11 +510,11 @@ paths:
$ref: "#/components/responses/InternalServerError"
post:
tags:
- Chart repositories
- Repositories
security:
- ApiKeyAuth: []
- CookieAuth: []
summary: Add organization's chart repository
summary: Add organization's repository
parameters:
- $ref: "#/components/parameters/OrgNameParam"
requestBody:
@ -522,7 +522,7 @@ paths:
content:
application/json:
schema:
$ref: "#/components/schemas/ChartRepositorySummary"
$ref: "#/components/schemas/RepositorySummary"
responses:
"201":
$ref: "#/components/responses/Created"
@ -536,23 +536,23 @@ paths:
$ref: "#/components/responses/TooManyRequests"
"500":
$ref: "#/components/responses/InternalServerError"
"/chart-repositories/org/{orgName}/{repoName}":
"/repositories/org/{orgName}/{repoName}":
put:
tags:
- Chart repositories
- Repositories
security:
- ApiKeyAuth: []
- CookieAuth: []
summary: Update organization's chart repository
summary: Update organization's repository
parameters:
- $ref: "#/components/parameters/OrgNameParam"
- $ref: "#/components/parameters/RepoNameParam"
requestBody:
description: Chart repository
description: Repository
content:
application/json:
schema:
$ref: "#/components/schemas/ChartRepositorySummary"
$ref: "#/components/schemas/RepositorySummary"
responses:
"204":
$ref: "#/components/responses/NoContent"
@ -568,11 +568,11 @@ paths:
$ref: "#/components/responses/InternalServerError"
delete:
tags:
- Chart repositories
- Repositories
security:
- ApiKeyAuth: []
- CookieAuth: []
summary: Delete organization's chart repository
summary: Delete organization's repository
parameters:
- $ref: "#/components/parameters/OrgNameParam"
- $ref: "#/components/parameters/RepoNameParam"
@ -587,14 +587,14 @@ paths:
$ref: "#/components/responses/TooManyRequests"
"500":
$ref: "#/components/responses/InternalServerError"
"/chart-repositories/org/{orgName}/{repoName}/transfer":
"/repositories/org/{orgName}/{repoName}/transfer":
put:
tags:
- Chart repositories
- Repositories
security:
- ApiKeyAuth: []
- CookieAuth: []
summary: Transfer organization's chart repository to a different owner
summary: Transfer organization's repository to a different owner
parameters:
- $ref: "#/components/parameters/OrgNameParam"
- $ref: "#/components/parameters/RepoNameParam"
@ -659,10 +659,10 @@ paths:
- $ref: "#/components/parameters/LimitParam"
- $ref: "#/components/parameters/FacetsParam"
- $ref: "#/components/parameters/TextParam"
- $ref: "#/components/parameters/PackageKindsListParam"
- $ref: "#/components/parameters/RepositoryKindsListParam"
- $ref: "#/components/parameters/UsersListParam"
- $ref: "#/components/parameters/OrgsListParam"
- $ref: "#/components/parameters/ChartRepositoriesListParam"
- $ref: "#/components/parameters/RepositoriesListParam"
- $ref: "#/components/parameters/DeprecatedParam"
responses:
"200":
@ -699,7 +699,6 @@ paths:
data:
packages:
- package_id: a9c77b9a-2cd1-4a8f-b9e8-6b8f94e13407
kind: 0
name: artifact-hub
normalized_name: artifact-hub
logo_image_id: 0f5488e2-da57-486b-a20f-bfe746ed3e23
@ -710,15 +709,15 @@ paths:
app_version: 0.1.0
deprecated: false
signed: null
user_alias: null
organization_name: artifacthub
organization_display_name: Artifact Hub
chart_repository:
repository:
kind: 0
name: artifact-hub
display_name: Artifact Hub
chart_repository_id: a032a436-3568-4970-804a-2780f5e9d231
repository_id: a032a436-3568-4970-804a-2780f5e9d231
user_alias: null
organization_name: artifacthub
organization_display_name: Artifact Hub
- package_id: 3af7b6a1-adbd-41f1-ad96-e1eb3350b019
kind: 0
name: sentry-kubernetes
normalized_name: sentry-kubernetes
logo_image_id: 55f2ed75-015d-4edd-9990-11fb2ffcae9e
@ -729,15 +728,15 @@ paths:
app_version: latest
deprecated: false
signed: null
user_alias: null
organization_name: helm
organization_display_name: Helm
chart_repository:
repository:
kind: 0
name: incubator
display_name: Incubator
chart_repository_id: dba459d0-6beb-451a-b15a-52d67cc93fa0
repository_id: dba459d0-6beb-451a-b15a-52d67cc93fa0
user_alias: null
organization_name: helm
organization_display_name: Helm
- package_id: 0d38123f-fb60-41f0-bd00-76fb331bf7ed
kind: 0
name: etcd-operator
normalized_name: etcd-operator
logo_image_id: 5gt2ed75-015d-40dd-9990-11fb2tgcae9e
@ -748,13 +747,14 @@ paths:
app_version: 0.9.4
deprecated: false
signed: null
user_alias: null
organization_name: helm
organization_display_name: Helm
chart_repository:
repository:
kind: 0
name: stable
display_name: Stable
chart_repository_id: dba484d0-6beb-451s-i85a-52d67iu73fa0
repository_id: dba484d0-6beb-451s-i85a-52d67iu73fa0
user_alias: null
organization_name: helm
organization_display_name: Helm
facets:
- title: Organization
filter_key: org
@ -771,7 +771,7 @@ paths:
- id: 0
name: Helm charts
total: 54
- title: Chart Repository
- title: Repository
filter_key: repo
options:
- id: stable
@ -816,12 +816,13 @@ paths:
$ref: "#/components/responses/TooManyRequests"
"500":
$ref: "#/components/responses/InternalServerError"
"/packages/chart/{repoName}/{packageName}":
"/packages/{^helm$|^falco$|^opa$}/{repoName}/{packageName}":
get:
tags:
- Packages
summary: Get package details
parameters:
- $ref: "#/components/parameters/RepoKindParam"
- $ref: "#/components/parameters/RepoNameParam"
- $ref: "#/components/parameters/PackageNameParam"
responses:
@ -837,12 +838,13 @@ paths:
$ref: "#/components/responses/TooManyRequests"
"500":
$ref: "#/components/responses/InternalServerError"
"/packages/chart/{repoName}/{packageName}/{version}":
"/packages/{^helm$|^falco$|^opa$}/{repoName}/{packageName}/{version}":
get:
tags:
- Packages
summary: Get package version details
parameters:
- $ref: "#/components/parameters/RepoKindParam"
- $ref: "#/components/parameters/RepoNameParam"
- $ref: "#/components/parameters/PackageNameParam"
- $ref: "#/components/parameters/VersionParam"
@ -859,49 +861,6 @@ paths:
$ref: "#/components/responses/TooManyRequests"
"500":
$ref: "#/components/responses/InternalServerError"
"/packages/{^falco$|^opa$}/{packageName}":
get:
tags:
- Packages
summary: Get package details
parameters:
- $ref: "#/components/parameters/FalcoOPAParam"
- $ref: "#/components/parameters/PackageNameParam"
responses:
"200":
description: ""
content:
application/json:
schema:
$ref: "#/components/schemas/Package"
"404":
$ref: "#/components/responses/NotFoundResponse"
"429":
$ref: "#/components/responses/TooManyRequests"
"500":
$ref: "#/components/responses/InternalServerError"
"/packages/{^falco$|^opa$}/{packageName}/{version}":
get:
tags:
- Packages
summary: Get package version details
parameters:
- $ref: "#/components/parameters/FalcoOPAParam"
- $ref: "#/components/parameters/PackageNameParam"
- $ref: "#/components/parameters/VersionParam"
responses:
"200":
description: ""
content:
application/json:
schema:
$ref: "#/components/schemas/Package"
"404":
$ref: "#/components/responses/NotFoundResponse"
"429":
$ref: "#/components/responses/TooManyRequests"
"500":
$ref: "#/components/responses/InternalServerError"
"/packages/{packageID}/stars":
get:
tags:
@ -964,8 +923,6 @@ paths:
package_id:
type: string
format: uuid
kind:
$ref: "#/components/schemas/PackageKind"
name:
type: string
nullable: false
@ -976,24 +933,26 @@ paths:
logo_image_id:
type: string
example: "12345abcde"
user_alias:
type: string
example: jdoe
organization_name:
type: string
example: org1
organization_display_name:
type: string
example: Organization 1
chart_repository:
repository:
type: object
properties:
kind:
$ref: "#/components/schemas/RepositoryKind"
name:
type: string
example: repo1
display_name:
type: string
example: Chart repo 1
example: Repo 1
user_alias:
type: string
example: jdoe
organization_name:
type: string
example: org1
organization_display_name:
type: string
example: Organization 1
"401":
$ref: "#/components/responses/UnauthorizedError"
"429":
@ -1349,12 +1308,12 @@ components:
in: cookie
name: sid
schemas:
ChartRepository:
Repository:
allOf:
- $ref: "#/components/schemas/ChartRepositorySummary"
- $ref: "#/components/schemas/RepositorySummary"
- type: object
properties:
chart_repository_id:
repository_id:
type: string
format: uuid
last_tracking_ts:
@ -1363,7 +1322,7 @@ components:
last_tracking_errors:
type: string
example: Error
ChartRepositorySummary:
RepositorySummary:
type: object
properties:
name:
@ -1523,24 +1482,26 @@ components:
created_at:
type: integer
example: 1552082346
PackageKind:
RepositoryKind:
type: integer
enum:
- 0
- 1
- 2
description: |
Package kind:
Repository kind:
* `0` - Helm charts
* `1` - Falco rules
* `2` - OPA policies
PackageKindName:
RepoKindParam:
type: string
enum:
- helm
- opa
- falco
description: |
Package kind name:
Repository kind name:
* `helm` - Helm charts
* `falco` - Falco rules
* `opa` - OPA policies
PackageSummary:
@ -1549,8 +1510,6 @@ components:
package_id:
type: string
format: uuid
kind:
$ref: "#/components/schemas/PackageKind"
name:
type: string
nullable: false
@ -1585,21 +1544,14 @@ components:
nullable: true
created_at:
type: integer
user_alias:
type: string
example: jdoe
organization_name:
type: string
example: org1
organization_display_name:
type: string
example: Organization 1
chart_repository:
repository:
type: object
properties:
chart_repository_id:
repository_id:
type: string
format: uuid
kind:
$ref: "#/components/schemas/RepositoryKind"
name:
type: string
nullable: false
@ -1607,7 +1559,16 @@ components:
display_name:
type: string
example: Repository 1
nullable: true
user_alias:
type: string
example: jdoe
organization_name:
type: string
example: org1
organization_display_name:
type: string
example: Organization 1
nullable: false
Organization:
allOf:
- $ref: "#/components/schemas/OrganizationSummary"
@ -1642,14 +1603,14 @@ components:
ResourceKindName:
type: string
enum:
- chartRepositoryName
- chartRepositoryURL
- repositoryName
- repositoryURL
- organizationName
- userAlias
description: |
Resource kind name:
* `chartRepositoryName` - Chart repository name
* `chartRepositoryURL` - Chart repository URL
* `repositoryName` - Repository name
* `repositoryURL` - Repository URL
* `organizationName` - Organization name
* `userAlias` - User alias
User:
@ -1782,9 +1743,9 @@ components:
- url
- event_kinds
parameters:
ChartRepositoriesListParam:
RepositoriesListParam:
in: query
name: chart_repositories
name: repo
schema:
type: array
items:
@ -1793,7 +1754,7 @@ components:
- repo1
- repo2
required: false
description: List of chart repository names
description: List of repository names
DeprecatedParam:
in: query
name: deprecated
@ -1817,11 +1778,11 @@ components:
default: false
required: true
description: Whether we should get facets or not
FalcoOPAParam:
RepoKindParam:
in: path
name: ^falco$|^opa$
name: ^helm$|^falco$|^opa$
schema:
$ref: "#/components/schemas/PackageKindName"
$ref: "#/components/schemas/RepoKindParam"
required: true
description: Package kind name
LimitParam:
@ -1878,16 +1839,16 @@ components:
format: uuid
required: true
description: Package ID
PackageKindsListParam:
RepositoryKindsListParam:
in: query
name: package_kinds
name: kind
schema:
type: array
items:
$ref: "#/components/schemas/PackageKind"
$ref: "#/components/schemas/RepositoryKind"
required: false
description: |
Package kind:
Repository kind:
* `0` - Helm charts
* `1` - Falco rules
* `2` - OPA policies
@ -1906,7 +1867,7 @@ components:
type: string
example: repoName
required: true
description: Chart repository name
description: Repository name
ResourceKindNameParam:
in: path
name: resourceKind

View File

@ -1,38 +0,0 @@
package hub
import (
"context"
"helm.sh/helm/v3/pkg/repo"
)
// ChartRepository represents a Helm chart repository.
type ChartRepository struct {
ChartRepositoryID string `json:"chart_repository_id"`
Name string `json:"name"`
DisplayName string `json:"display_name"`
URL string `json:"url"`
UserID string `json:"user_id"`
}
// ChartRepositoryManager describes the methods an ChartRepositoryManager
// implementation must provide.
type ChartRepositoryManager interface {
Add(ctx context.Context, orgName string, r *ChartRepository) error
CheckAvailability(ctx context.Context, resourceKind, value string) (bool, error)
Delete(ctx context.Context, name string) error
GetAll(ctx context.Context) ([]*ChartRepository, error)
GetByName(ctx context.Context, name string) (*ChartRepository, error)
GetPackagesDigest(ctx context.Context, chartRepositoryID string) (map[string]string, error)
GetOwnedByOrgJSON(ctx context.Context, orgName string) ([]byte, error)
GetOwnedByUserJSON(ctx context.Context) ([]byte, error)
SetLastTrackingResults(ctx context.Context, chartRepositoryID, errs string) error
Transfer(ctx context.Context, name, orgName string) error
Update(ctx context.Context, r *ChartRepository) error
}
// ChartRepositoryIndexLoader interface defines the methods a chart repository
// index loader implementation should provide.
type ChartRepositoryIndexLoader interface {
LoadIndex(r *ChartRepository) (*repo.IndexFile, error)
}

View File

@ -3,7 +3,7 @@ package hub
import "context"
// Organization represents an entity with one or more users associated that can
// own packages and other entities like chart repositories.
// own repositories and other entities like webhooks.
type Organization struct {
OrganizationID string `json:"organization_id"`
Name string `json:"name"`

View File

@ -4,10 +4,10 @@ import "context"
// GetPackageInput represents the input used to get a specific package.
type GetPackageInput struct {
PackageID string `json:"package_id"`
ChartRepositoryName string `json:"chart_repository_name"`
PackageName string `json:"package_name"`
Version string `json:"version"`
PackageID string `json:"package_id"`
RepositoryName string `json:"repository_name"`
PackageName string `json:"package_name"`
Version string `json:"version"`
}
// Link represents a url associated with a package.
@ -31,51 +31,31 @@ type Maintainer struct {
// Package represents a Kubernetes package.
type Package struct {
PackageID string `json:"package_id"`
Kind PackageKind `json:"kind"`
Name string `json:"name"`
NormalizedName string `json:"normalized_name"`
LogoURL string `json:"logo_url"`
LogoImageID string `json:"logo_image_id"`
DisplayName string `json:"display_name"`
Description string `json:"description"`
Keywords []string `json:"keywords"`
HomeURL string `json:"home_url"`
Readme string `json:"readme"`
Links []*Link `json:"links"`
Data map[string]interface{} `json:"data"`
Version string `json:"version"`
AvailableVersions []*Version `json:"available_versions"`
AppVersion string `json:"app_version"`
Digest string `json:"digest"`
Deprecated bool `json:"deprecated"`
License string `json:"license"`
Signed bool `json:"signed"`
ContentURL string `json:"content_url"`
Maintainers []*Maintainer `json:"maintainers"`
UserID string `json:"user_id"`
UserAlias string `json:"user_alias"`
OrganizationID string `json:"organization_id"`
OrganizationName string `json:"organization_name"`
OrganizationDisplayName string `json:"organization_display_name"`
ChartRepository *ChartRepository `json:"chart_repository"`
CreatedAt int64 `json:"created_at,omitempty"`
PackageID string `json:"package_id"`
Name string `json:"name"`
NormalizedName string `json:"normalized_name"`
LogoURL string `json:"logo_url"`
LogoImageID string `json:"logo_image_id"`
DisplayName string `json:"display_name"`
Description string `json:"description"`
Keywords []string `json:"keywords"`
HomeURL string `json:"home_url"`
Readme string `json:"readme"`
Links []*Link `json:"links"`
Data map[string]interface{} `json:"data"`
Version string `json:"version"`
AvailableVersions []*Version `json:"available_versions"`
AppVersion string `json:"app_version"`
Digest string `json:"digest"`
Deprecated bool `json:"deprecated"`
License string `json:"license"`
Signed bool `json:"signed"`
ContentURL string `json:"content_url"`
Maintainers []*Maintainer `json:"maintainers"`
Repository *Repository `json:"repository"`
CreatedAt int64 `json:"created_at,omitempty"`
}
// PackageKind represents the kind of a given package.
type PackageKind int64
const (
// Chart represents a Helm chart.
Chart PackageKind = 0
// Falco represents a set of Falco rules.
Falco PackageKind = 1
// OPA represents a set of OPA policies.
OPA PackageKind = 2
)
// PackageManager describes the methods a PackageManager implementation must
// provide.
type PackageManager interface {
@ -93,13 +73,13 @@ type PackageManager interface {
// SearchPackageInput represents the query input when searching for packages.
type SearchPackageInput struct {
Limit int `json:"limit,omitempty"`
Offset int `json:"offset,omitempty"`
Facets bool `json:"facets"`
Text string `json:"text"`
PackageKinds []PackageKind `json:"package_kinds,omitempty"`
Users []string `json:"users,omitempty"`
Orgs []string `json:"orgs,omitempty"`
ChartRepositories []string `json:"chart_repositories,omitempty"`
Deprecated bool `json:"deprecated"`
Limit int `json:"limit,omitempty"`
Offset int `json:"offset,omitempty"`
Facets bool `json:"facets"`
Text string `json:"text"`
Users []string `json:"users,omitempty"`
Orgs []string `json:"orgs,omitempty"`
Repositories []string `json:"repositories,omitempty"`
RepositoryKinds []RepositoryKind `json:"repository_kinds,omitempty"`
Deprecated bool `json:"deprecated"`
}

76
internal/hub/repo.go Normal file
View File

@ -0,0 +1,76 @@
package hub
import (
"context"
helmrepo "helm.sh/helm/v3/pkg/repo"
)
// RepositoryKind represents the kind of a given repository.
type RepositoryKind int64
const (
// Helm represents a repository with Helm charts.
Helm RepositoryKind = 0
// Falco represents a repository with Falco rules.
Falco RepositoryKind = 1
// OPA represents a repository with OPA policies.
OPA RepositoryKind = 2
// OLM represents a repository with OLM operators.
OLM RepositoryKind = 3
)
// GetKindName returns the name of the provided repository kind.
func GetKindName(kind RepositoryKind) string {
switch kind {
case Helm:
return "helm"
case Falco:
return "falco"
case OPA:
return "opa"
case OLM:
return "olm"
default:
return ""
}
}
// Repository represents a packages repository.
type Repository struct {
RepositoryID string `json:"repository_id"`
Name string `json:"name"`
DisplayName string `json:"display_name"`
URL string `json:"url"`
Kind RepositoryKind `json:"kind"`
UserID string `json:"user_id"`
UserAlias string `json:"user_alias"`
OrganizationID string `json:"organization_id"`
OrganizationName string `json:"organization_name"`
OrganizationDisplayName string `json:"organization_display_name"`
}
// RepositoryManager describes the methods an RepositoryManager
// implementation must provide.
type RepositoryManager interface {
Add(ctx context.Context, orgName string, r *Repository) error
CheckAvailability(ctx context.Context, resourceKind, value string) (bool, error)
Delete(ctx context.Context, name string) error
GetByKind(ctx context.Context, kind RepositoryKind) ([]*Repository, error)
GetByName(ctx context.Context, name string) (*Repository, error)
GetPackagesDigest(ctx context.Context, repositoryID string) (map[string]string, error)
GetOwnedByOrgJSON(ctx context.Context, orgName string) ([]byte, error)
GetOwnedByUserJSON(ctx context.Context) ([]byte, error)
SetLastTrackingResults(ctx context.Context, repositoryID, errs string) error
Transfer(ctx context.Context, name, orgName string) error
Update(ctx context.Context, r *Repository) error
}
// HelmIndexLoader interface defines the methods a Helm index loader
// implementation should provide.
type HelmIndexLoader interface {
LoadIndex(r *Repository) (*helmrepo.IndexFile, error)
}

View File

@ -109,7 +109,7 @@ var newReleaseEmailTmpl = template.Must(template.New("").Parse(`
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top; text-align: center;">
<img style="margin: 30px;" height="40px" src="{{ .BaseURL }}{{ if .Package.logoImageID }}/image/{{ .Package.logoImageID }}@3x{{ else }}/static/media/kubernetes_grey.svg{{ end }}">
<img style="margin: 30px;" height="40px" src="{{ .BaseURL }}{{ if .Package.logoImageID }}/image/{{ .Package.logoImageID }}@3x{{ else }}/static/media/package_placeholder.svg{{ end }}">
<h2 style="color: #39596c; font-family: sans-serif; margin: 0; Margin-bottom: 15px;"><img style="margin-right: 5px; margin-bottom: -2px;" height="18px" src="{{ .BaseURL }}/static/media/{{ .Package.kind }}.svg">{{ .Package.name }}</h2>
<h4 style="color: #1c2c35; font-family: sans-serif; margin: 0; Margin-bottom: 15px;">{{ .Package.publisher }} </h4>

View File

@ -215,7 +215,7 @@ func (w *Worker) prepareEmailData(ctx context.Context, e *hub.Event) (email.Data
// prepareTemplateData prepares the data available to notifications templates.
func (w *Worker) prepareTemplateData(ctx context.Context, e *hub.Event) (*hub.NotificationTemplateData, error) {
// Get notification package
// Get notification package (try from cache first)
var p *hub.Package
cKey := "package.%" + e.EventID
cValue, ok := w.cache.Get(cKey)
@ -239,29 +239,16 @@ func (w *Worker) prepareTemplateData(ctx context.Context, e *hub.Event) (*hub.No
case hub.NewRelease:
eventKindStr = "package.new-release"
}
publisher := p.OrganizationName
publisher := p.Repository.OrganizationName
if publisher == "" {
publisher = p.UserAlias
}
if p.ChartRepository != nil {
publisher += "/" + p.ChartRepository.Name
}
var packageKindStr, packagePath string
switch p.Kind {
case hub.Chart:
packageKindStr = "helm-chart"
packagePath = fmt.Sprintf("/packages/chart/%s/%s/%s",
p.ChartRepository.Name,
p.NormalizedName,
e.PackageVersion,
)
case hub.Falco:
packageKindStr = "falco-rules"
packagePath = fmt.Sprintf("/packages/falco/%s/%s", p.NormalizedName, e.PackageVersion)
case hub.OPA:
packageKindStr = "opa-policies"
packagePath = fmt.Sprintf("/packages/opa/%s/%s", p.NormalizedName, e.PackageVersion)
publisher = p.Repository.UserAlias
}
packagePath := fmt.Sprintf("/packages/%s/%s/%s/%s",
hub.GetKindName(p.Repository.Kind),
p.Repository.Name,
p.NormalizedName,
e.PackageVersion,
)
return &hub.NotificationTemplateData{
BaseURL: w.baseURL,
@ -270,12 +257,15 @@ func (w *Worker) prepareTemplateData(ctx context.Context, e *hub.Event) (*hub.No
"kind": eventKindStr,
},
Package: map[string]interface{}{
"kind": packageKindStr,
"name": p.Name,
"version": p.Version,
"logoImageID": p.LogoImageID,
"publisher": publisher,
"url": w.baseURL + packagePath,
"repository": map[string]interface{}{
"kind": hub.GetKindName(p.Repository.Kind),
"name": p.Repository.Name,
"publisher": publisher,
},
},
}, nil
}
@ -291,11 +281,14 @@ var DefaultWebhookPayloadTmpl = template.Must(template.New("").Parse(`
"datacontenttype" : "application/json",
"data" : {
"package": {
"kind": "{{ .Package.kind }}",
"name": "{{ .Package.name }}",
"version": "{{ .Package.version }}",
"publisher": "{{ .Package.publisher }}",
"url": "{{ .Package.url }}"
"url": "{{ .Package.url }}",
"repository": {
"kind": "{{ .Package.repository.kind }}",
"name": "{{ .Package.repository.name }}",
"publisher": "{{ .Package.repository.publisher }}"
}
}
}
}

View File

@ -49,13 +49,13 @@ func TestWorker(t *testing.T) {
Version: e.PackageVersion,
}
p := &hub.Package{
Kind: 0,
Name: "package1",
NormalizedName: "package1",
Version: "1.0.0",
OrganizationName: "org1",
ChartRepository: &hub.ChartRepository{
Name: "repo1",
Name: "package1",
NormalizedName: "package1",
Version: "1.0.0",
Repository: &hub.Repository{
Kind: hub.Helm,
Name: "repo1",
OrganizationName: "org1",
},
}
@ -192,11 +192,14 @@ func TestWorker(t *testing.T) {
"datacontenttype" : "application/json",
"data" : {
"package": {
"kind": "helm-chart",
"name": "package1",
"version": "1.0.0",
"publisher": "org1/repo1",
"url": "http://baseURL/packages/chart/repo1/package1/1.0.0"
"url": "http://baseURL/packages/helm/repo1/package1/1.0.0",
"repository": {
"kind": "helm",
"name": "repo1",
"publisher": "org1"
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More