mirror of
https://github.com/goharbor/harbor.git
synced 2025-02-02 21:11:37 +01:00
Implement tag service interface
This commit is contained in:
parent
3044a154b1
commit
54df5ec053
@ -11,6 +11,30 @@ export interface Base {
|
|||||||
update_time?: Date;
|
update_time?: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for tag history
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface TagCompatibility
|
||||||
|
*/
|
||||||
|
export interface TagCompatibility {
|
||||||
|
v1Compatibility: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for tag manifest
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface TagManifest
|
||||||
|
*/
|
||||||
|
export interface TagManifest {
|
||||||
|
schemaVersion: number;
|
||||||
|
name: string;
|
||||||
|
tag: string;
|
||||||
|
architecture: string;
|
||||||
|
history: TagCompatibility[];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for Repository
|
* Interface for Repository
|
||||||
*
|
*
|
||||||
@ -35,7 +59,11 @@ export interface Repository extends Base {
|
|||||||
* @interface Tag
|
* @interface Tag
|
||||||
* @extends {Base}
|
* @extends {Base}
|
||||||
*/
|
*/
|
||||||
export interface Tag extends Base { }
|
export interface Tag extends Base {
|
||||||
|
tag: string;
|
||||||
|
manifest: TagManifest;
|
||||||
|
signed?: number; //May NOT exist
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for registry endpoints.
|
* Interface for registry endpoints.
|
||||||
@ -69,14 +97,14 @@ export interface ReplicationJob { }
|
|||||||
* @interface AccessLog
|
* @interface AccessLog
|
||||||
*/
|
*/
|
||||||
export interface AccessLog {
|
export interface AccessLog {
|
||||||
log_id: number,
|
log_id: number;
|
||||||
project_id: number,
|
project_id: number;
|
||||||
repo_name: string,
|
repo_name: string;
|
||||||
repo_tag: string,
|
repo_tag: string;
|
||||||
operation: string,
|
operation: string;
|
||||||
op_time: string | Date,
|
op_time: string | Date;
|
||||||
user_id: number,
|
user_id: number;
|
||||||
username: string,
|
username: string;
|
||||||
keywords?: string, //NOT used now
|
keywords?: string; //NOT used now
|
||||||
guid?: string //NOT used now
|
guid?: string; //NOT used now
|
||||||
}
|
}
|
@ -1,15 +1,62 @@
|
|||||||
import { TestBed, inject } from '@angular/core/testing';
|
import { TestBed, inject, async } from '@angular/core/testing';
|
||||||
|
|
||||||
import { TagService, TagDefaultService } from './tag.service';
|
import { TagService, TagDefaultService } from './tag.service';
|
||||||
|
import { SharedModule } from '../shared/shared.module';
|
||||||
|
import { SERVICE_CONFIG, IServiceConfig } from '../service.config';
|
||||||
|
|
||||||
|
import { Tag, TagCompatibility, TagManifest } from './interface';
|
||||||
|
|
||||||
|
import { VerifiedSignature } from './tag.service';
|
||||||
|
import { toPromise } from '../utils';
|
||||||
|
|
||||||
describe('TagService', () => {
|
describe('TagService', () => {
|
||||||
|
let mockComp: TagCompatibility[] = [{
|
||||||
|
v1Compatibility: '{"architecture":"amd64","author":"NGINX Docker Maintainers \\"docker-maint@nginx.com\\"","config":{"Hostname":"6b3797ab1e90","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"ExposedPorts":{"443/tcp":{},"80/tcp":{}},"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","NGINX_VERSION=1.11.5-1~jessie"],"Cmd":["nginx","-g","daemon off;"],"ArgsEscaped":true,"Image":"sha256:47a33f0928217b307cf9f20920a0c6445b34ae974a60c1b4fe73b809379ad928","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":[],"Labels":{}},"container":"f1883a3fb44b0756a2a3b1e990736a44b1387183125351370042ce7bd9ffc338","container_config":{"Hostname":"6b3797ab1e90","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"ExposedPorts":{"443/tcp":{},"80/tcp":{}},"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","NGINX_VERSION=1.11.5-1~jessie"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\\"nginx\\" \\"-g\\" \\"daemon off;\\"]"],"ArgsEscaped":true,"Image":"sha256:47a33f0928217b307cf9f20920a0c6445b34ae974a60c1b4fe73b809379ad928","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":[],"Labels":{}},"created":"2016-11-08T22:41:15.912313785Z","docker_version":"1.12.3","id":"db3700426e6d7c1402667f42917109b2467dd49daa85d38ac99854449edc20b3","os":"linux","parent":"f3ef5f96caf99a18c6821487102c136b00e0275b1da0c7558d7090351f9d447e","throwaway":true}'
|
||||||
|
}];
|
||||||
|
let mockManifest: TagManifest = {
|
||||||
|
schemaVersion: 1,
|
||||||
|
name: 'library/nginx',
|
||||||
|
tag: '1.11.5',
|
||||||
|
architecture: 'amd64',
|
||||||
|
history: mockComp
|
||||||
|
};
|
||||||
|
|
||||||
|
let mockTags: Tag[] = [{
|
||||||
|
tag: '1.11.5',
|
||||||
|
manifest: mockManifest
|
||||||
|
}];
|
||||||
|
|
||||||
|
let mockSignatures: VerifiedSignature[] = [{
|
||||||
|
tag: '1.11.5',
|
||||||
|
hashes: {
|
||||||
|
sha256: 'fake'
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
let mockSignatures2: VerifiedSignature[] = [{
|
||||||
|
tag: '1.11.15',
|
||||||
|
hashes: {
|
||||||
|
sha256: 'fake2'
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
const mockConfig: IServiceConfig = {
|
||||||
|
repositoryBaseEndpoint: "/api/repositories/testing"
|
||||||
|
};
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
SharedModule
|
||||||
|
],
|
||||||
providers: [
|
providers: [
|
||||||
TagDefaultService,
|
TagDefaultService,
|
||||||
{
|
{
|
||||||
provide: TagService,
|
provide: TagService,
|
||||||
useClass: TagDefaultService
|
useClass: TagDefaultService
|
||||||
|
}, {
|
||||||
|
provide: SERVICE_CONFIG,
|
||||||
|
useValue: mockConfig
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -17,4 +64,51 @@ describe('TagService', () => {
|
|||||||
it('should be initialized', inject([TagDefaultService], (service: TagService) => {
|
it('should be initialized', inject([TagDefaultService], (service: TagService) => {
|
||||||
expect(service).toBeTruthy();
|
expect(service).toBeTruthy();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should get tags with signed status[1] if signatures exists', async(inject([TagDefaultService], (service: TagService) => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
let spy1: jasmine.Spy = spyOn(service, '_getTags')
|
||||||
|
.and.returnValue(Promise.resolve(mockTags));
|
||||||
|
let spy2: jasmine.Spy = spyOn(service, '_getSignatures')
|
||||||
|
.and.returnValue(Promise.resolve(mockSignatures));
|
||||||
|
|
||||||
|
toPromise<Tag[]>(service.getTags('library/nginx'))
|
||||||
|
.then(tags => {
|
||||||
|
expect(tags).toBeTruthy();
|
||||||
|
expect(tags.length).toBe(1);
|
||||||
|
expect(tags[0].signed).toBe(1);
|
||||||
|
});
|
||||||
|
})));
|
||||||
|
|
||||||
|
it('should get tags with not-signed status[0] if signatures exists', async(inject([TagDefaultService], (service: TagService) => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
let spy1: jasmine.Spy = spyOn(service, '_getTags')
|
||||||
|
.and.returnValue(Promise.resolve(mockTags));
|
||||||
|
let spy2: jasmine.Spy = spyOn(service, '_getSignatures')
|
||||||
|
.and.returnValue(Promise.resolve(mockSignatures2));
|
||||||
|
|
||||||
|
toPromise<Tag[]>(service.getTags('library/nginx'))
|
||||||
|
.then(tags => {
|
||||||
|
expect(tags).toBeTruthy();
|
||||||
|
expect(tags.length).toBe(1);
|
||||||
|
expect(tags[0].signed).toBe(0);
|
||||||
|
});
|
||||||
|
})));
|
||||||
|
|
||||||
|
it('should get tags with default signed status[-1] if signatures not exist', async(inject([TagDefaultService], (service: TagService) => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
let spy1: jasmine.Spy = spyOn(service, '_getTags')
|
||||||
|
.and.returnValue(Promise.resolve(mockTags));
|
||||||
|
let spy2: jasmine.Spy = spyOn(service, '_getSignatures')
|
||||||
|
.and.returnValue(Promise.reject("Error"));
|
||||||
|
|
||||||
|
toPromise<Tag[]>(service.getTags('library/nginx'))
|
||||||
|
.then(tags => {
|
||||||
|
expect(tags).toBeTruthy();
|
||||||
|
expect(tags.length).toBe(1);
|
||||||
|
expect(tags[0].signed).toBe(-1);
|
||||||
|
});
|
||||||
|
})));
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1,8 +1,25 @@
|
|||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { RequestQueryParams } from './RequestQueryParams';
|
import { RequestQueryParams } from './RequestQueryParams';
|
||||||
import { Tag } from './interface';
|
import { Tag } from './interface';
|
||||||
import { Injectable } from "@angular/core";
|
import { Injectable, Inject } from "@angular/core";
|
||||||
import 'rxjs/add/observable/of';
|
import 'rxjs/add/observable/of';
|
||||||
|
import { Http } from '@angular/http';
|
||||||
|
import { SERVICE_CONFIG, IServiceConfig } from '../service.config';
|
||||||
|
import { buildHttpRequestOptions, HTTP_JSON_OPTIONS } from '../utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For getting tag signatures.
|
||||||
|
* This is temporary, will be removed in future.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class VerifiedSignature
|
||||||
|
*/
|
||||||
|
export class VerifiedSignature {
|
||||||
|
tag: string;
|
||||||
|
hashes: {
|
||||||
|
sha256: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the service methods to handle the repository tag related things.
|
* Define the service methods to handle the repository tag related things.
|
||||||
@ -19,11 +36,11 @@ export abstract class TagService {
|
|||||||
* @abstract
|
* @abstract
|
||||||
* @param {string} repositoryName
|
* @param {string} repositoryName
|
||||||
* @param {RequestQueryParams} [queryParams]
|
* @param {RequestQueryParams} [queryParams]
|
||||||
* @returns {(Observable<Tag[]> | Tag[])}
|
* @returns {(Observable<Tag[]> | Promise<Tag[]> | Tag[])}
|
||||||
*
|
*
|
||||||
* @memberOf TagService
|
* @memberOf TagService
|
||||||
*/
|
*/
|
||||||
abstract getTags(repositoryName: string, queryParams?: RequestQueryParams): Observable<Tag[]> | Tag[];
|
abstract getTags(repositoryName: string, queryParams?: RequestQueryParams): Observable<Tag[]> | Promise<Tag[]> | Tag[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the specified tag.
|
* Delete the specified tag.
|
||||||
@ -35,7 +52,7 @@ export abstract class TagService {
|
|||||||
*
|
*
|
||||||
* @memberOf TagService
|
* @memberOf TagService
|
||||||
*/
|
*/
|
||||||
abstract deleteTag(repositoryName: string, tag: string): Observable<any> | any;
|
abstract deleteTag(repositoryName: string, tag: string): Observable<any> | Promise<Tag> | any;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,11 +64,73 @@ export abstract class TagService {
|
|||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TagDefaultService extends TagService {
|
export class TagDefaultService extends TagService {
|
||||||
public getTags(repositoryName: string, queryParams?: RequestQueryParams): Observable<Tag[]> | Tag[] {
|
_baseUrl: string;
|
||||||
return Observable.of([]);
|
|
||||||
|
constructor(
|
||||||
|
private http: Http,
|
||||||
|
@Inject(SERVICE_CONFIG) private config: IServiceConfig
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
this._baseUrl = this.config.repositoryBaseEndpoint ? this.config.repositoryBaseEndpoint : '/api/repositories';
|
||||||
}
|
}
|
||||||
|
|
||||||
public deleteTag(repositoryName: string, tag: string): Observable<any> | any {
|
//Private methods
|
||||||
return Observable.of({});
|
//These two methods are temporary, will be deleted in future after API refactored
|
||||||
|
_getTags(repositoryName: string, queryParams?: RequestQueryParams): Promise<Tag[]> {
|
||||||
|
if (!queryParams) {
|
||||||
|
queryParams = new RequestQueryParams();
|
||||||
|
}
|
||||||
|
|
||||||
|
queryParams.set('detail', '1');
|
||||||
|
let url: string = `${this._baseUrl}/${repositoryName}/tags`;
|
||||||
|
|
||||||
|
return this.http.get(url, buildHttpRequestOptions(queryParams)).toPromise()
|
||||||
|
.then(response => response.json() as Tag[])
|
||||||
|
.catch(error => Promise.reject(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
_getSignatures(repositoryName: string): Promise<VerifiedSignature[]> {
|
||||||
|
let url: string = `${this._baseUrl}/${repositoryName}/signatures`;
|
||||||
|
return this.http.get(url, HTTP_JSON_OPTIONS).toPromise()
|
||||||
|
.then(response => response.json() as VerifiedSignature[])
|
||||||
|
.catch(error => Promise.reject(error))
|
||||||
|
}
|
||||||
|
|
||||||
|
public getTags(repositoryName: string, queryParams?: RequestQueryParams): Observable<Tag[]> | Promise<Tag[]> | Tag[] {
|
||||||
|
if (!repositoryName) {
|
||||||
|
return Promise.reject("Bad argument");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._getTags(repositoryName, queryParams)
|
||||||
|
.then(tags => {
|
||||||
|
return this._getSignatures(repositoryName)
|
||||||
|
.then(signatures => {
|
||||||
|
tags.forEach(tag => {
|
||||||
|
let foundOne: VerifiedSignature | undefined = signatures.find(signature => signature.tag === tag.tag);
|
||||||
|
if (foundOne) {
|
||||||
|
tag.signed = 1;//Signed
|
||||||
|
} else {
|
||||||
|
tag.signed = 0;//Not signed
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return tags;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
tags.forEach(tag => tag.signed = -1);//No signature info
|
||||||
|
return tags;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(error => Promise.reject(error))
|
||||||
|
}
|
||||||
|
|
||||||
|
public deleteTag(repositoryName: string, tag: string): Observable<any> | Promise<Tag> | any {
|
||||||
|
if (!repositoryName || !tag) {
|
||||||
|
return Promise.reject("Bad argument");
|
||||||
|
}
|
||||||
|
|
||||||
|
let url: string = `${this._baseUrl}/${repositoryName}/tags/${tag}`;
|
||||||
|
return this.http.delete(url, HTTP_JSON_OPTIONS).toPromise()
|
||||||
|
.then(response => response)
|
||||||
|
.catch(error => Promise.reject(error));
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user