1
0
Fork 0

rewrite artifacts client to have public and internal implementations

pull/1591/head
Rob Herley 2023-11-30 03:47:04 +00:00 committed by GitHub
parent 0787a93181
commit 695bf98f84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1149 additions and 254 deletions

View File

@ -90,6 +90,105 @@ export interface FinalizeArtifactResponse {
*/ */
artifactId: string; artifactId: string;
} }
/**
* @generated from protobuf message github.actions.results.api.v1.ListArtifactsRequest
*/
export interface ListArtifactsRequest {
/**
* The backend plan ID
*
* @generated from protobuf field: string workflow_run_backend_id = 1;
*/
workflowRunBackendId: string;
/**
* The backend job ID
*
* @generated from protobuf field: string workflow_job_run_backend_id = 2;
*/
workflowJobRunBackendId: string;
/**
* (optional) Name of the artifact to filter on
*
* @generated from protobuf field: string name_filter = 3;
*/
nameFilter: string;
/**
* (optional) Monolith Database ID of the artifact to filter on
*
* @generated from protobuf field: int64 id_filter = 4;
*/
idFilter: string;
}
/**
* @generated from protobuf message github.actions.results.api.v1.ListArtifactsResponse
*/
export interface ListArtifactsResponse {
/**
* @generated from protobuf field: repeated github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact artifacts = 1;
*/
artifacts: ListArtifactsResponse_MonolithArtifact[];
}
/**
* @generated from protobuf message github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact
*/
export interface ListArtifactsResponse_MonolithArtifact {
/**
* The backend plan ID
*
* @generated from protobuf field: string workflow_run_backend_id = 1;
*/
workflowRunBackendId: string;
/**
* The backend job ID
*
* @generated from protobuf field: string workflow_job_run_backend_id = 2;
*/
workflowJobRunBackendId: string;
/**
* Monolith database ID of the artifact
*
* @generated from protobuf field: int64 database_id = 3;
*/
databaseId: string;
/**
* Name of the artifact
*
* @generated from protobuf field: string name = 4;
*/
name: string;
/**
* Size of the artifact in bytes
*
* @generated from protobuf field: int64 size = 5;
*/
size: string;
}
/**
* @generated from protobuf message github.actions.results.api.v1.GetSignedArtifactURLRequest
*/
export interface GetSignedArtifactURLRequest {
/**
* @generated from protobuf field: string workflow_run_backend_id = 1;
*/
workflowRunBackendId: string;
/**
* @generated from protobuf field: string workflow_job_run_backend_id = 2;
*/
workflowJobRunBackendId: string;
/**
* @generated from protobuf field: string name = 3;
*/
name: string;
}
/**
* @generated from protobuf message github.actions.results.api.v1.GetSignedArtifactURLResponse
*/
export interface GetSignedArtifactURLResponse {
/**
* @generated from protobuf field: string signed_url = 1;
*/
signedUrl: string;
}
// @generated message type with reflection information, may provide speed optimized methods // @generated message type with reflection information, may provide speed optimized methods
class CreateArtifactRequest$Type extends MessageType<CreateArtifactRequest> { class CreateArtifactRequest$Type extends MessageType<CreateArtifactRequest> {
constructor() { constructor() {
@ -348,10 +447,310 @@ class FinalizeArtifactResponse$Type extends MessageType<FinalizeArtifactResponse
* @generated MessageType for protobuf message github.actions.results.api.v1.FinalizeArtifactResponse * @generated MessageType for protobuf message github.actions.results.api.v1.FinalizeArtifactResponse
*/ */
export const FinalizeArtifactResponse = new FinalizeArtifactResponse$Type(); export const FinalizeArtifactResponse = new FinalizeArtifactResponse$Type();
// @generated message type with reflection information, may provide speed optimized methods
class ListArtifactsRequest$Type extends MessageType<ListArtifactsRequest> {
constructor() {
super("github.actions.results.api.v1.ListArtifactsRequest", [
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 2, name: "workflow_job_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 3, name: "name_filter", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 4, name: "id_filter", kind: "scalar", T: 3 /*ScalarType.INT64*/ }
]);
}
create(value?: PartialMessage<ListArtifactsRequest>): ListArtifactsRequest {
const message = { workflowRunBackendId: "", workflowJobRunBackendId: "", nameFilter: "", idFilter: "0" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<ListArtifactsRequest>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListArtifactsRequest): ListArtifactsRequest {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string workflow_run_backend_id */ 1:
message.workflowRunBackendId = reader.string();
break;
case /* string workflow_job_run_backend_id */ 2:
message.workflowJobRunBackendId = reader.string();
break;
case /* string name_filter */ 3:
message.nameFilter = reader.string();
break;
case /* int64 id_filter */ 4:
message.idFilter = reader.int64().toString();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: ListArtifactsRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string workflow_run_backend_id = 1; */
if (message.workflowRunBackendId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.workflowRunBackendId);
/* string workflow_job_run_backend_id = 2; */
if (message.workflowJobRunBackendId !== "")
writer.tag(2, WireType.LengthDelimited).string(message.workflowJobRunBackendId);
/* string name_filter = 3; */
if (message.nameFilter !== "")
writer.tag(3, WireType.LengthDelimited).string(message.nameFilter);
/* int64 id_filter = 4; */
if (message.idFilter !== "0")
writer.tag(4, WireType.Varint).int64(message.idFilter);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message github.actions.results.api.v1.ListArtifactsRequest
*/
export const ListArtifactsRequest = new ListArtifactsRequest$Type();
// @generated message type with reflection information, may provide speed optimized methods
class ListArtifactsResponse$Type extends MessageType<ListArtifactsResponse> {
constructor() {
super("github.actions.results.api.v1.ListArtifactsResponse", [
{ no: 1, name: "artifacts", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => ListArtifactsResponse_MonolithArtifact }
]);
}
create(value?: PartialMessage<ListArtifactsResponse>): ListArtifactsResponse {
const message = { artifacts: [] };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<ListArtifactsResponse>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListArtifactsResponse): ListArtifactsResponse {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* repeated github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact artifacts */ 1:
message.artifacts.push(ListArtifactsResponse_MonolithArtifact.internalBinaryRead(reader, reader.uint32(), options));
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: ListArtifactsResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* repeated github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact artifacts = 1; */
for (let i = 0; i < message.artifacts.length; i++)
ListArtifactsResponse_MonolithArtifact.internalBinaryWrite(message.artifacts[i], writer.tag(1, WireType.LengthDelimited).fork(), options).join();
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message github.actions.results.api.v1.ListArtifactsResponse
*/
export const ListArtifactsResponse = new ListArtifactsResponse$Type();
// @generated message type with reflection information, may provide speed optimized methods
class ListArtifactsResponse_MonolithArtifact$Type extends MessageType<ListArtifactsResponse_MonolithArtifact> {
constructor() {
super("github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact", [
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 2, name: "workflow_job_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 3, name: "database_id", kind: "scalar", T: 3 /*ScalarType.INT64*/ },
{ no: 4, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 5, name: "size", kind: "scalar", T: 3 /*ScalarType.INT64*/ }
]);
}
create(value?: PartialMessage<ListArtifactsResponse_MonolithArtifact>): ListArtifactsResponse_MonolithArtifact {
const message = { workflowRunBackendId: "", workflowJobRunBackendId: "", databaseId: "0", name: "", size: "0" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<ListArtifactsResponse_MonolithArtifact>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListArtifactsResponse_MonolithArtifact): ListArtifactsResponse_MonolithArtifact {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string workflow_run_backend_id */ 1:
message.workflowRunBackendId = reader.string();
break;
case /* string workflow_job_run_backend_id */ 2:
message.workflowJobRunBackendId = reader.string();
break;
case /* int64 database_id */ 3:
message.databaseId = reader.int64().toString();
break;
case /* string name */ 4:
message.name = reader.string();
break;
case /* int64 size */ 5:
message.size = reader.int64().toString();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: ListArtifactsResponse_MonolithArtifact, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string workflow_run_backend_id = 1; */
if (message.workflowRunBackendId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.workflowRunBackendId);
/* string workflow_job_run_backend_id = 2; */
if (message.workflowJobRunBackendId !== "")
writer.tag(2, WireType.LengthDelimited).string(message.workflowJobRunBackendId);
/* int64 database_id = 3; */
if (message.databaseId !== "0")
writer.tag(3, WireType.Varint).int64(message.databaseId);
/* string name = 4; */
if (message.name !== "")
writer.tag(4, WireType.LengthDelimited).string(message.name);
/* int64 size = 5; */
if (message.size !== "0")
writer.tag(5, WireType.Varint).int64(message.size);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact
*/
export const ListArtifactsResponse_MonolithArtifact = new ListArtifactsResponse_MonolithArtifact$Type();
// @generated message type with reflection information, may provide speed optimized methods
class GetSignedArtifactURLRequest$Type extends MessageType<GetSignedArtifactURLRequest> {
constructor() {
super("github.actions.results.api.v1.GetSignedArtifactURLRequest", [
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 2, name: "workflow_job_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 3, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
]);
}
create(value?: PartialMessage<GetSignedArtifactURLRequest>): GetSignedArtifactURLRequest {
const message = { workflowRunBackendId: "", workflowJobRunBackendId: "", name: "" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<GetSignedArtifactURLRequest>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetSignedArtifactURLRequest): GetSignedArtifactURLRequest {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string workflow_run_backend_id */ 1:
message.workflowRunBackendId = reader.string();
break;
case /* string workflow_job_run_backend_id */ 2:
message.workflowJobRunBackendId = reader.string();
break;
case /* string name */ 3:
message.name = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: GetSignedArtifactURLRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string workflow_run_backend_id = 1; */
if (message.workflowRunBackendId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.workflowRunBackendId);
/* string workflow_job_run_backend_id = 2; */
if (message.workflowJobRunBackendId !== "")
writer.tag(2, WireType.LengthDelimited).string(message.workflowJobRunBackendId);
/* string name = 3; */
if (message.name !== "")
writer.tag(3, WireType.LengthDelimited).string(message.name);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message github.actions.results.api.v1.GetSignedArtifactURLRequest
*/
export const GetSignedArtifactURLRequest = new GetSignedArtifactURLRequest$Type();
// @generated message type with reflection information, may provide speed optimized methods
class GetSignedArtifactURLResponse$Type extends MessageType<GetSignedArtifactURLResponse> {
constructor() {
super("github.actions.results.api.v1.GetSignedArtifactURLResponse", [
{ no: 1, name: "signed_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
]);
}
create(value?: PartialMessage<GetSignedArtifactURLResponse>): GetSignedArtifactURLResponse {
const message = { signedUrl: "" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<GetSignedArtifactURLResponse>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetSignedArtifactURLResponse): GetSignedArtifactURLResponse {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string signed_url */ 1:
message.signedUrl = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: GetSignedArtifactURLResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string signed_url = 1; */
if (message.signedUrl !== "")
writer.tag(1, WireType.LengthDelimited).string(message.signedUrl);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message github.actions.results.api.v1.GetSignedArtifactURLResponse
*/
export const GetSignedArtifactURLResponse = new GetSignedArtifactURLResponse$Type();
/** /**
* @generated ServiceType for protobuf service github.actions.results.api.v1.ArtifactService * @generated ServiceType for protobuf service github.actions.results.api.v1.ArtifactService
*/ */
export const ArtifactService = new ServiceType("github.actions.results.api.v1.ArtifactService", [ export const ArtifactService = new ServiceType("github.actions.results.api.v1.ArtifactService", [
{ name: "CreateArtifact", options: {}, I: CreateArtifactRequest, O: CreateArtifactResponse }, { name: "CreateArtifact", options: {}, I: CreateArtifactRequest, O: CreateArtifactResponse },
{ name: "FinalizeArtifact", options: {}, I: FinalizeArtifactRequest, O: FinalizeArtifactResponse } { name: "FinalizeArtifact", options: {}, I: FinalizeArtifactRequest, O: FinalizeArtifactResponse },
{ name: "ListArtifacts", options: {}, I: ListArtifactsRequest, O: ListArtifactsResponse },
{ name: "GetSignedArtifactURL", options: {}, I: GetSignedArtifactURLRequest, O: GetSignedArtifactURLResponse }
]); ]);

View File

@ -6,14 +6,18 @@ import {
TwirpErrorCode, TwirpErrorCode,
Interceptor, Interceptor,
TwirpContentType, TwirpContentType,
chainInterceptors chainInterceptors,
} from 'twirp-ts' } from "twirp-ts";
import { import {
CreateArtifactRequest, CreateArtifactRequest,
CreateArtifactResponse, CreateArtifactResponse,
FinalizeArtifactRequest, FinalizeArtifactRequest,
FinalizeArtifactResponse FinalizeArtifactResponse,
} from './artifact' ListArtifactsRequest,
ListArtifactsResponse,
GetSignedArtifactURLRequest,
GetSignedArtifactURLResponse,
} from "./artifact";
//==================================// //==================================//
// Client Code // // Client Code //
@ -23,43 +27,51 @@ interface Rpc {
request( request(
service: string, service: string,
method: string, method: string,
contentType: 'application/json' | 'application/protobuf', contentType: "application/json" | "application/protobuf",
data: object | Uint8Array data: object | Uint8Array
): Promise<object | Uint8Array> ): Promise<object | Uint8Array>;
} }
export interface ArtifactServiceClient { export interface ArtifactServiceClient {
CreateArtifact( CreateArtifact(
request: CreateArtifactRequest request: CreateArtifactRequest
): Promise<CreateArtifactResponse> ): Promise<CreateArtifactResponse>;
FinalizeArtifact( FinalizeArtifact(
request: FinalizeArtifactRequest request: FinalizeArtifactRequest
): Promise<FinalizeArtifactResponse> ): Promise<FinalizeArtifactResponse>;
ListArtifacts(request: ListArtifactsRequest): Promise<ListArtifactsResponse>;
GetSignedArtifactURL(
request: GetSignedArtifactURLRequest
): Promise<GetSignedArtifactURLResponse>;
} }
export class ArtifactServiceClientJSON implements ArtifactServiceClient { export class ArtifactServiceClientJSON implements ArtifactServiceClient {
private readonly rpc: Rpc private readonly rpc: Rpc;
constructor(rpc: Rpc) { constructor(rpc: Rpc) {
this.rpc = rpc this.rpc = rpc;
this.CreateArtifact.bind(this) this.CreateArtifact.bind(this);
this.FinalizeArtifact.bind(this) this.FinalizeArtifact.bind(this);
this.ListArtifacts.bind(this);
this.GetSignedArtifactURL.bind(this);
} }
CreateArtifact( CreateArtifact(
request: CreateArtifactRequest request: CreateArtifactRequest
): Promise<CreateArtifactResponse> { ): Promise<CreateArtifactResponse> {
const data = CreateArtifactRequest.toJson(request, { const data = CreateArtifactRequest.toJson(request, {
useProtoFieldName: true, useProtoFieldName: true,
emitDefaultValues: false emitDefaultValues: false,
}) });
const promise = this.rpc.request( const promise = this.rpc.request(
'github.actions.results.api.v1.ArtifactService', "github.actions.results.api.v1.ArtifactService",
'CreateArtifact', "CreateArtifact",
'application/json', "application/json",
data as object data as object
) );
return promise.then(data => return promise.then((data) =>
CreateArtifactResponse.fromJson(data as any, {ignoreUnknownFields: true}) CreateArtifactResponse.fromJson(data as any, {
) ignoreUnknownFields: true,
})
);
} }
FinalizeArtifact( FinalizeArtifact(
@ -67,57 +79,123 @@ export class ArtifactServiceClientJSON implements ArtifactServiceClient {
): Promise<FinalizeArtifactResponse> { ): Promise<FinalizeArtifactResponse> {
const data = FinalizeArtifactRequest.toJson(request, { const data = FinalizeArtifactRequest.toJson(request, {
useProtoFieldName: true, useProtoFieldName: true,
emitDefaultValues: false emitDefaultValues: false,
}) });
const promise = this.rpc.request( const promise = this.rpc.request(
'github.actions.results.api.v1.ArtifactService', "github.actions.results.api.v1.ArtifactService",
'FinalizeArtifact', "FinalizeArtifact",
'application/json', "application/json",
data as object data as object
) );
return promise.then(data => return promise.then((data) =>
FinalizeArtifactResponse.fromJson(data as any, { FinalizeArtifactResponse.fromJson(data as any, {
ignoreUnknownFields: true ignoreUnknownFields: true,
}) })
) );
}
ListArtifacts(request: ListArtifactsRequest): Promise<ListArtifactsResponse> {
const data = ListArtifactsRequest.toJson(request, {
useProtoFieldName: true,
emitDefaultValues: false,
});
const promise = this.rpc.request(
"github.actions.results.api.v1.ArtifactService",
"ListArtifacts",
"application/json",
data as object
);
return promise.then((data) =>
ListArtifactsResponse.fromJson(data as any, { ignoreUnknownFields: true })
);
}
GetSignedArtifactURL(
request: GetSignedArtifactURLRequest
): Promise<GetSignedArtifactURLResponse> {
const data = GetSignedArtifactURLRequest.toJson(request, {
useProtoFieldName: true,
emitDefaultValues: false,
});
const promise = this.rpc.request(
"github.actions.results.api.v1.ArtifactService",
"GetSignedArtifactURL",
"application/json",
data as object
);
return promise.then((data) =>
GetSignedArtifactURLResponse.fromJson(data as any, {
ignoreUnknownFields: true,
})
);
} }
} }
export class ArtifactServiceClientProtobuf implements ArtifactServiceClient { export class ArtifactServiceClientProtobuf implements ArtifactServiceClient {
private readonly rpc: Rpc private readonly rpc: Rpc;
constructor(rpc: Rpc) { constructor(rpc: Rpc) {
this.rpc = rpc this.rpc = rpc;
this.CreateArtifact.bind(this) this.CreateArtifact.bind(this);
this.FinalizeArtifact.bind(this) this.FinalizeArtifact.bind(this);
this.ListArtifacts.bind(this);
this.GetSignedArtifactURL.bind(this);
} }
CreateArtifact( CreateArtifact(
request: CreateArtifactRequest request: CreateArtifactRequest
): Promise<CreateArtifactResponse> { ): Promise<CreateArtifactResponse> {
const data = CreateArtifactRequest.toBinary(request) const data = CreateArtifactRequest.toBinary(request);
const promise = this.rpc.request( const promise = this.rpc.request(
'github.actions.results.api.v1.ArtifactService', "github.actions.results.api.v1.ArtifactService",
'CreateArtifact', "CreateArtifact",
'application/protobuf', "application/protobuf",
data data
) );
return promise.then(data => return promise.then((data) =>
CreateArtifactResponse.fromBinary(data as Uint8Array) CreateArtifactResponse.fromBinary(data as Uint8Array)
) );
} }
FinalizeArtifact( FinalizeArtifact(
request: FinalizeArtifactRequest request: FinalizeArtifactRequest
): Promise<FinalizeArtifactResponse> { ): Promise<FinalizeArtifactResponse> {
const data = FinalizeArtifactRequest.toBinary(request) const data = FinalizeArtifactRequest.toBinary(request);
const promise = this.rpc.request( const promise = this.rpc.request(
'github.actions.results.api.v1.ArtifactService', "github.actions.results.api.v1.ArtifactService",
'FinalizeArtifact', "FinalizeArtifact",
'application/protobuf', "application/protobuf",
data data
) );
return promise.then(data => return promise.then((data) =>
FinalizeArtifactResponse.fromBinary(data as Uint8Array) FinalizeArtifactResponse.fromBinary(data as Uint8Array)
) );
}
ListArtifacts(request: ListArtifactsRequest): Promise<ListArtifactsResponse> {
const data = ListArtifactsRequest.toBinary(request);
const promise = this.rpc.request(
"github.actions.results.api.v1.ArtifactService",
"ListArtifacts",
"application/protobuf",
data
);
return promise.then((data) =>
ListArtifactsResponse.fromBinary(data as Uint8Array)
);
}
GetSignedArtifactURL(
request: GetSignedArtifactURLRequest
): Promise<GetSignedArtifactURLResponse> {
const data = GetSignedArtifactURLRequest.toBinary(request);
const promise = this.rpc.request(
"github.actions.results.api.v1.ArtifactService",
"GetSignedArtifactURL",
"application/protobuf",
data
);
return promise.then((data) =>
GetSignedArtifactURLResponse.fromBinary(data as Uint8Array)
);
} }
} }
@ -129,33 +207,45 @@ export interface ArtifactServiceTwirp<T extends TwirpContext = TwirpContext> {
CreateArtifact( CreateArtifact(
ctx: T, ctx: T,
request: CreateArtifactRequest request: CreateArtifactRequest
): Promise<CreateArtifactResponse> ): Promise<CreateArtifactResponse>;
FinalizeArtifact( FinalizeArtifact(
ctx: T, ctx: T,
request: FinalizeArtifactRequest request: FinalizeArtifactRequest
): Promise<FinalizeArtifactResponse> ): Promise<FinalizeArtifactResponse>;
ListArtifacts(
ctx: T,
request: ListArtifactsRequest
): Promise<ListArtifactsResponse>;
GetSignedArtifactURL(
ctx: T,
request: GetSignedArtifactURLRequest
): Promise<GetSignedArtifactURLResponse>;
} }
export enum ArtifactServiceMethod { export enum ArtifactServiceMethod {
CreateArtifact = 'CreateArtifact', CreateArtifact = "CreateArtifact",
FinalizeArtifact = 'FinalizeArtifact' FinalizeArtifact = "FinalizeArtifact",
ListArtifacts = "ListArtifacts",
GetSignedArtifactURL = "GetSignedArtifactURL",
} }
export const ArtifactServiceMethodList = [ export const ArtifactServiceMethodList = [
ArtifactServiceMethod.CreateArtifact, ArtifactServiceMethod.CreateArtifact,
ArtifactServiceMethod.FinalizeArtifact ArtifactServiceMethod.FinalizeArtifact,
] ArtifactServiceMethod.ListArtifacts,
ArtifactServiceMethod.GetSignedArtifactURL,
];
export function createArtifactServiceServer< export function createArtifactServiceServer<
T extends TwirpContext = TwirpContext T extends TwirpContext = TwirpContext
>(service: ArtifactServiceTwirp<T>) { >(service: ArtifactServiceTwirp<T>) {
return new TwirpServer<ArtifactServiceTwirp, T>({ return new TwirpServer<ArtifactServiceTwirp, T>({
service, service,
packageName: 'github.actions.results.api.v1', packageName: "github.actions.results.api.v1",
serviceName: 'ArtifactService', serviceName: "ArtifactService",
methodList: ArtifactServiceMethodList, methodList: ArtifactServiceMethodList,
matchRoute: matchArtifactServiceRoute matchRoute: matchArtifactServiceRoute,
}) });
} }
function matchArtifactServiceRoute<T extends TwirpContext = TwirpContext>( function matchArtifactServiceRoute<T extends TwirpContext = TwirpContext>(
@ -163,7 +253,7 @@ function matchArtifactServiceRoute<T extends TwirpContext = TwirpContext>(
events: RouterEvents<T> events: RouterEvents<T>
) { ) {
switch (method) { switch (method) {
case 'CreateArtifact': case "CreateArtifact":
return async ( return async (
ctx: T, ctx: T,
service: ArtifactServiceTwirp, service: ArtifactServiceTwirp,
@ -174,16 +264,16 @@ function matchArtifactServiceRoute<T extends TwirpContext = TwirpContext>(
CreateArtifactResponse CreateArtifactResponse
>[] >[]
) => { ) => {
ctx = {...ctx, methodName: 'CreateArtifact'} ctx = { ...ctx, methodName: "CreateArtifact" };
await events.onMatch(ctx) await events.onMatch(ctx);
return handleArtifactServiceCreateArtifactRequest( return handleArtifactServiceCreateArtifactRequest(
ctx, ctx,
service, service,
data, data,
interceptors interceptors
) );
} };
case 'FinalizeArtifact': case "FinalizeArtifact":
return async ( return async (
ctx: T, ctx: T,
service: ArtifactServiceTwirp, service: ArtifactServiceTwirp,
@ -194,19 +284,59 @@ function matchArtifactServiceRoute<T extends TwirpContext = TwirpContext>(
FinalizeArtifactResponse FinalizeArtifactResponse
>[] >[]
) => { ) => {
ctx = {...ctx, methodName: 'FinalizeArtifact'} ctx = { ...ctx, methodName: "FinalizeArtifact" };
await events.onMatch(ctx) await events.onMatch(ctx);
return handleArtifactServiceFinalizeArtifactRequest( return handleArtifactServiceFinalizeArtifactRequest(
ctx, ctx,
service, service,
data, data,
interceptors interceptors
) );
} };
case "ListArtifacts":
return async (
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<
T,
ListArtifactsRequest,
ListArtifactsResponse
>[]
) => {
ctx = { ...ctx, methodName: "ListArtifacts" };
await events.onMatch(ctx);
return handleArtifactServiceListArtifactsRequest(
ctx,
service,
data,
interceptors
);
};
case "GetSignedArtifactURL":
return async (
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<
T,
GetSignedArtifactURLRequest,
GetSignedArtifactURLResponse
>[]
) => {
ctx = { ...ctx, methodName: "GetSignedArtifactURL" };
await events.onMatch(ctx);
return handleArtifactServiceGetSignedArtifactURLRequest(
ctx,
service,
data,
interceptors
);
};
default: default:
events.onNotFound() events.onNotFound();
const msg = `no handler found` const msg = `no handler found`;
throw new TwirpError(TwirpErrorCode.BadRoute, msg) throw new TwirpError(TwirpErrorCode.BadRoute, msg);
} }
} }
@ -225,17 +355,17 @@ function handleArtifactServiceCreateArtifactRequest<
service, service,
data, data,
interceptors interceptors
) );
case TwirpContentType.Protobuf: case TwirpContentType.Protobuf:
return handleArtifactServiceCreateArtifactProtobuf<T>( return handleArtifactServiceCreateArtifactProtobuf<T>(
ctx, ctx,
service, service,
data, data,
interceptors interceptors
) );
default: default:
const msg = 'unexpected Content-Type' const msg = "unexpected Content-Type";
throw new TwirpError(TwirpErrorCode.BadRoute, msg) throw new TwirpError(TwirpErrorCode.BadRoute, msg);
} }
} }
@ -258,17 +388,79 @@ function handleArtifactServiceFinalizeArtifactRequest<
service, service,
data, data,
interceptors interceptors
) );
case TwirpContentType.Protobuf: case TwirpContentType.Protobuf:
return handleArtifactServiceFinalizeArtifactProtobuf<T>( return handleArtifactServiceFinalizeArtifactProtobuf<T>(
ctx, ctx,
service, service,
data, data,
interceptors interceptors
) );
default: default:
const msg = 'unexpected Content-Type' const msg = "unexpected Content-Type";
throw new TwirpError(TwirpErrorCode.BadRoute, msg) throw new TwirpError(TwirpErrorCode.BadRoute, msg);
}
}
function handleArtifactServiceListArtifactsRequest<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<T, ListArtifactsRequest, ListArtifactsResponse>[]
): Promise<string | Uint8Array> {
switch (ctx.contentType) {
case TwirpContentType.JSON:
return handleArtifactServiceListArtifactsJSON<T>(
ctx,
service,
data,
interceptors
);
case TwirpContentType.Protobuf:
return handleArtifactServiceListArtifactsProtobuf<T>(
ctx,
service,
data,
interceptors
);
default:
const msg = "unexpected Content-Type";
throw new TwirpError(TwirpErrorCode.BadRoute, msg);
}
}
function handleArtifactServiceGetSignedArtifactURLRequest<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<
T,
GetSignedArtifactURLRequest,
GetSignedArtifactURLResponse
>[]
): Promise<string | Uint8Array> {
switch (ctx.contentType) {
case TwirpContentType.JSON:
return handleArtifactServiceGetSignedArtifactURLJSON<T>(
ctx,
service,
data,
interceptors
);
case TwirpContentType.Protobuf:
return handleArtifactServiceGetSignedArtifactURLProtobuf<T>(
ctx,
service,
data,
interceptors
);
default:
const msg = "unexpected Content-Type";
throw new TwirpError(TwirpErrorCode.BadRoute, msg);
} }
} }
async function handleArtifactServiceCreateArtifactJSON< async function handleArtifactServiceCreateArtifactJSON<
@ -279,16 +471,18 @@ async function handleArtifactServiceCreateArtifactJSON<
data: Buffer, data: Buffer,
interceptors?: Interceptor<T, CreateArtifactRequest, CreateArtifactResponse>[] interceptors?: Interceptor<T, CreateArtifactRequest, CreateArtifactResponse>[]
) { ) {
let request: CreateArtifactRequest let request: CreateArtifactRequest;
let response: CreateArtifactResponse let response: CreateArtifactResponse;
try { try {
const body = JSON.parse(data.toString() || '{}') const body = JSON.parse(data.toString() || "{}");
request = CreateArtifactRequest.fromJson(body, {ignoreUnknownFields: true}) request = CreateArtifactRequest.fromJson(body, {
ignoreUnknownFields: true,
});
} catch (e) { } catch (e) {
if (e instanceof Error) { if (e instanceof Error) {
const msg = 'the json request could not be decoded' const msg = "the json request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true) throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
} }
} }
@ -297,20 +491,20 @@ async function handleArtifactServiceCreateArtifactJSON<
T, T,
CreateArtifactRequest, CreateArtifactRequest,
CreateArtifactResponse CreateArtifactResponse
> >;
response = await interceptor(ctx, request!, (ctx, inputReq) => { response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.CreateArtifact(ctx, inputReq) return service.CreateArtifact(ctx, inputReq);
}) });
} else { } else {
response = await service.CreateArtifact(ctx, request!) response = await service.CreateArtifact(ctx, request!);
} }
return JSON.stringify( return JSON.stringify(
CreateArtifactResponse.toJson(response, { CreateArtifactResponse.toJson(response, {
useProtoFieldName: true, useProtoFieldName: true,
emitDefaultValues: false emitDefaultValues: false,
}) as string }) as string
) );
} }
async function handleArtifactServiceFinalizeArtifactJSON< async function handleArtifactServiceFinalizeArtifactJSON<
@ -325,18 +519,18 @@ async function handleArtifactServiceFinalizeArtifactJSON<
FinalizeArtifactResponse FinalizeArtifactResponse
>[] >[]
) { ) {
let request: FinalizeArtifactRequest let request: FinalizeArtifactRequest;
let response: FinalizeArtifactResponse let response: FinalizeArtifactResponse;
try { try {
const body = JSON.parse(data.toString() || '{}') const body = JSON.parse(data.toString() || "{}");
request = FinalizeArtifactRequest.fromJson(body, { request = FinalizeArtifactRequest.fromJson(body, {
ignoreUnknownFields: true ignoreUnknownFields: true,
}) });
} catch (e) { } catch (e) {
if (e instanceof Error) { if (e instanceof Error) {
const msg = 'the json request could not be decoded' const msg = "the json request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true) throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
} }
} }
@ -345,20 +539,112 @@ async function handleArtifactServiceFinalizeArtifactJSON<
T, T,
FinalizeArtifactRequest, FinalizeArtifactRequest,
FinalizeArtifactResponse FinalizeArtifactResponse
> >;
response = await interceptor(ctx, request!, (ctx, inputReq) => { response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.FinalizeArtifact(ctx, inputReq) return service.FinalizeArtifact(ctx, inputReq);
}) });
} else { } else {
response = await service.FinalizeArtifact(ctx, request!) response = await service.FinalizeArtifact(ctx, request!);
} }
return JSON.stringify( return JSON.stringify(
FinalizeArtifactResponse.toJson(response, { FinalizeArtifactResponse.toJson(response, {
useProtoFieldName: true, useProtoFieldName: true,
emitDefaultValues: false emitDefaultValues: false,
}) as string }) as string
) );
}
async function handleArtifactServiceListArtifactsJSON<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<T, ListArtifactsRequest, ListArtifactsResponse>[]
) {
let request: ListArtifactsRequest;
let response: ListArtifactsResponse;
try {
const body = JSON.parse(data.toString() || "{}");
request = ListArtifactsRequest.fromJson(body, {
ignoreUnknownFields: true,
});
} catch (e) {
if (e instanceof Error) {
const msg = "the json request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
}
}
if (interceptors && interceptors.length > 0) {
const interceptor = chainInterceptors(...interceptors) as Interceptor<
T,
ListArtifactsRequest,
ListArtifactsResponse
>;
response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.ListArtifacts(ctx, inputReq);
});
} else {
response = await service.ListArtifacts(ctx, request!);
}
return JSON.stringify(
ListArtifactsResponse.toJson(response, {
useProtoFieldName: true,
emitDefaultValues: false,
}) as string
);
}
async function handleArtifactServiceGetSignedArtifactURLJSON<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<
T,
GetSignedArtifactURLRequest,
GetSignedArtifactURLResponse
>[]
) {
let request: GetSignedArtifactURLRequest;
let response: GetSignedArtifactURLResponse;
try {
const body = JSON.parse(data.toString() || "{}");
request = GetSignedArtifactURLRequest.fromJson(body, {
ignoreUnknownFields: true,
});
} catch (e) {
if (e instanceof Error) {
const msg = "the json request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
}
}
if (interceptors && interceptors.length > 0) {
const interceptor = chainInterceptors(...interceptors) as Interceptor<
T,
GetSignedArtifactURLRequest,
GetSignedArtifactURLResponse
>;
response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.GetSignedArtifactURL(ctx, inputReq);
});
} else {
response = await service.GetSignedArtifactURL(ctx, request!);
}
return JSON.stringify(
GetSignedArtifactURLResponse.toJson(response, {
useProtoFieldName: true,
emitDefaultValues: false,
}) as string
);
} }
async function handleArtifactServiceCreateArtifactProtobuf< async function handleArtifactServiceCreateArtifactProtobuf<
T extends TwirpContext = TwirpContext T extends TwirpContext = TwirpContext
@ -368,15 +654,15 @@ async function handleArtifactServiceCreateArtifactProtobuf<
data: Buffer, data: Buffer,
interceptors?: Interceptor<T, CreateArtifactRequest, CreateArtifactResponse>[] interceptors?: Interceptor<T, CreateArtifactRequest, CreateArtifactResponse>[]
) { ) {
let request: CreateArtifactRequest let request: CreateArtifactRequest;
let response: CreateArtifactResponse let response: CreateArtifactResponse;
try { try {
request = CreateArtifactRequest.fromBinary(data) request = CreateArtifactRequest.fromBinary(data);
} catch (e) { } catch (e) {
if (e instanceof Error) { if (e instanceof Error) {
const msg = 'the protobuf request could not be decoded' const msg = "the protobuf request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true) throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
} }
} }
@ -385,15 +671,15 @@ async function handleArtifactServiceCreateArtifactProtobuf<
T, T,
CreateArtifactRequest, CreateArtifactRequest,
CreateArtifactResponse CreateArtifactResponse
> >;
response = await interceptor(ctx, request!, (ctx, inputReq) => { response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.CreateArtifact(ctx, inputReq) return service.CreateArtifact(ctx, inputReq);
}) });
} else { } else {
response = await service.CreateArtifact(ctx, request!) response = await service.CreateArtifact(ctx, request!);
} }
return Buffer.from(CreateArtifactResponse.toBinary(response)) return Buffer.from(CreateArtifactResponse.toBinary(response));
} }
async function handleArtifactServiceFinalizeArtifactProtobuf< async function handleArtifactServiceFinalizeArtifactProtobuf<
@ -408,15 +694,15 @@ async function handleArtifactServiceFinalizeArtifactProtobuf<
FinalizeArtifactResponse FinalizeArtifactResponse
>[] >[]
) { ) {
let request: FinalizeArtifactRequest let request: FinalizeArtifactRequest;
let response: FinalizeArtifactResponse let response: FinalizeArtifactResponse;
try { try {
request = FinalizeArtifactRequest.fromBinary(data) request = FinalizeArtifactRequest.fromBinary(data);
} catch (e) { } catch (e) {
if (e instanceof Error) { if (e instanceof Error) {
const msg = 'the protobuf request could not be decoded' const msg = "the protobuf request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true) throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
} }
} }
@ -425,13 +711,89 @@ async function handleArtifactServiceFinalizeArtifactProtobuf<
T, T,
FinalizeArtifactRequest, FinalizeArtifactRequest,
FinalizeArtifactResponse FinalizeArtifactResponse
> >;
response = await interceptor(ctx, request!, (ctx, inputReq) => { response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.FinalizeArtifact(ctx, inputReq) return service.FinalizeArtifact(ctx, inputReq);
}) });
} else { } else {
response = await service.FinalizeArtifact(ctx, request!) response = await service.FinalizeArtifact(ctx, request!);
} }
return Buffer.from(FinalizeArtifactResponse.toBinary(response)) return Buffer.from(FinalizeArtifactResponse.toBinary(response));
}
async function handleArtifactServiceListArtifactsProtobuf<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<T, ListArtifactsRequest, ListArtifactsResponse>[]
) {
let request: ListArtifactsRequest;
let response: ListArtifactsResponse;
try {
request = ListArtifactsRequest.fromBinary(data);
} catch (e) {
if (e instanceof Error) {
const msg = "the protobuf request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
}
}
if (interceptors && interceptors.length > 0) {
const interceptor = chainInterceptors(...interceptors) as Interceptor<
T,
ListArtifactsRequest,
ListArtifactsResponse
>;
response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.ListArtifacts(ctx, inputReq);
});
} else {
response = await service.ListArtifacts(ctx, request!);
}
return Buffer.from(ListArtifactsResponse.toBinary(response));
}
async function handleArtifactServiceGetSignedArtifactURLProtobuf<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<
T,
GetSignedArtifactURLRequest,
GetSignedArtifactURLResponse
>[]
) {
let request: GetSignedArtifactURLRequest;
let response: GetSignedArtifactURLResponse;
try {
request = GetSignedArtifactURLRequest.fromBinary(data);
} catch (e) {
if (e instanceof Error) {
const msg = "the protobuf request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
}
}
if (interceptors && interceptors.length > 0) {
const interceptor = chainInterceptors(...interceptors) as Interceptor<
T,
GetSignedArtifactURLRequest,
GetSignedArtifactURLResponse
>;
response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.GetSignedArtifactURL(ctx, inputReq);
});
} else {
response = await service.GetSignedArtifactURL(ctx, request!);
}
return Buffer.from(GetSignedArtifactURLResponse.toBinary(response));
} }

View File

@ -6,12 +6,16 @@ import {
DownloadArtifactOptions, DownloadArtifactOptions,
GetArtifactResponse, GetArtifactResponse,
ListArtifactsResponse, ListArtifactsResponse,
DownloadArtifactResponse DownloadArtifactResponse,
LookupOptions
} from './shared/interfaces' } from './shared/interfaces'
import {uploadArtifact} from './upload/upload-artifact' import {uploadArtifact} from './upload/upload-artifact'
import {downloadArtifact} from './download/download-artifact' import {
import {getArtifact} from './find/get-artifact' downloadArtifactPublic,
import {listArtifacts} from './find/list-artifacts' downloadArtifactInternal
} from './download/download-artifact'
import {getArtifactPublic, getArtifactInternal} from './find/get-artifact'
import {listArtifactsPublic, listArtifactsInternal} from './find/list-artifacts'
export interface ArtifactClient { export interface ArtifactClient {
/** /**
@ -31,62 +35,46 @@ export interface ArtifactClient {
): Promise<UploadResponse> ): Promise<UploadResponse>
/** /**
* Lists all artifacts that are part of a workflow run. * Lists all artifacts that are part of the current workflow run.
* This function will return at most 1000 artifacts per workflow run.
* *
* This calls the public List-Artifacts API https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#list-workflow-run-artifacts * If options.token is specified, this will call the public List-Artifacts API which can list from other runs.
* Due to paginated responses from the public API. This function will return at most 1000 artifacts per workflow run (100 per page * maximum 10 calls) * https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#list-workflow-run-artifacts
* *
* @param workflowRunId The workflow run id that the artifact belongs to * @param options Extra options that allow for the customization of the list behavior
* @param repositoryOwner The owner of the repository that the artifact belongs to
* @param repositoryName The name of the repository that the artifact belongs to
* @param token A token with the appropriate permission to the repository to list artifacts
* @returns ListArtifactResponse object * @returns ListArtifactResponse object
*/ */
listArtifacts( listArtifacts(options?: LookupOptions): Promise<ListArtifactsResponse>
workflowRunId: number,
repositoryOwner: string,
repositoryName: string,
token: string
): Promise<ListArtifactsResponse>
/** /**
* Finds an artifact by name given a repository and workflow run id. * Finds an artifact by name.
* *
* This calls the public List-Artifacts API with a name filter https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#list-workflow-run-artifacts * If options.token is specified, this will use the public List Artifacts API with a name filter which can get artifacts from other runs.
* https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#list-workflow-run-artifacts
* @actions/artifact > 2.0.0 does not allow for creating multiple artifacts with the same name in the same workflow run. * @actions/artifact > 2.0.0 does not allow for creating multiple artifacts with the same name in the same workflow run.
* It is possible to have multiple artifacts with the same name in the same workflow run by using old versions of upload-artifact (v1,v2 and v3) or @actions/artifact < v2.0.0 * It is possible to have multiple artifacts with the same name in the same workflow run by using old versions of upload-artifact (v1,v2 and v3), @actions/artifact < v2.0.0 or it is a rerun.
* If there are multiple artifacts with the same name in the same workflow run this function will return the first artifact that matches the name. * If there are multiple artifacts with the same name in the same workflow run this function will return the first artifact that matches the name.
* *
* @param artifactName The name of the artifact to find * @param artifactName The name of the artifact to find
* @param workflowRunId The workflow run id that the artifact belongs to * @param options Extra options that allow for the customization of the get behavior
* @param repositoryOwner The owner of the repository that the artifact belongs to
* @param repositoryName The name of the repository that the artifact belongs to
* @param token A token with the appropriate permission to the repository to find the artifact
*/ */
getArtifact( getArtifact(
artifactName: string, artifactName: string,
workflowRunId: number, options?: LookupOptions
repositoryOwner: string,
repositoryName: string,
token: string
): Promise<GetArtifactResponse> ): Promise<GetArtifactResponse>
/** /**
* Downloads an artifact and unzips the content * Downloads an artifact and unzips the content.
*
* If options.token is specified, this will use the public Download Artifact API https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#download-an-artifact
* *
* @param artifactId The name of the artifact to download * @param artifactId The name of the artifact to download
* @param repositoryOwner The owner of the repository that the artifact belongs to
* @param repositoryName The name of the repository that the artifact belongs to
* @param token A token with the appropriate permission to the repository to download the artifact
* @param options Extra options that allow for the customization of the download behavior * @param options Extra options that allow for the customization of the download behavior
* @returns single DownloadArtifactResponse object * @returns single DownloadArtifactResponse object
*/ */
downloadArtifact( downloadArtifact(
artifactId: number, artifactId: number,
repositoryOwner: string, options?: DownloadArtifactOptions & LookupOptions
repositoryName: string,
token: string,
options?: DownloadArtifactOptions
): Promise<DownloadArtifactResponse> ): Promise<DownloadArtifactResponse>
} }
@ -137,10 +125,7 @@ If the error persists, please check whether Actions is operating normally at [ht
*/ */
async downloadArtifact( async downloadArtifact(
artifactId: number, artifactId: number,
repositoryOwner: string, options?: DownloadArtifactOptions & LookupOptions
repositoryName: string,
token: string,
options?: DownloadArtifactOptions
): Promise<DownloadArtifactResponse> { ): Promise<DownloadArtifactResponse> {
if (isGhes()) { if (isGhes()) {
warning( warning(
@ -152,13 +137,19 @@ If the error persists, please check whether Actions is operating normally at [ht
} }
try { try {
return downloadArtifact( if (options?.token) {
artifactId, const {repositoryOwner, repositoryName, token, ...downloadOptions} =
repositoryOwner, options
repositoryName, return downloadArtifactPublic(
token, artifactId,
options repositoryOwner,
) repositoryName,
token,
downloadOptions
)
}
return downloadArtifactInternal(artifactId)
} catch (error) { } catch (error) {
warning( warning(
`Artifact download failed with error: ${error}. `Artifact download failed with error: ${error}.
@ -177,12 +168,7 @@ If the error persists, please check whether Actions and API requests are operati
/** /**
* List Artifacts * List Artifacts
*/ */
async listArtifacts( async listArtifacts(options?: LookupOptions): Promise<ListArtifactsResponse> {
workflowRunId: number,
repositoryOwner: string,
repositoryName: string,
token: string
): Promise<ListArtifactsResponse> {
if (isGhes()) { if (isGhes()) {
warning( warning(
`@actions/artifact v2.0.0+ and download-artifact@v4+ are not currently supported on GHES.` `@actions/artifact v2.0.0+ and download-artifact@v4+ are not currently supported on GHES.`
@ -193,12 +179,16 @@ If the error persists, please check whether Actions and API requests are operati
} }
try { try {
return listArtifacts( if (options?.token) {
workflowRunId, return listArtifactsPublic(
repositoryOwner, options.workflowRunId,
repositoryName, options.repositoryOwner,
token options.repositoryName,
) options.token
)
}
return listArtifactsInternal()
} catch (error: unknown) { } catch (error: unknown) {
warning( warning(
`Listing Artifacts failed with error: ${error}. `Listing Artifacts failed with error: ${error}.
@ -219,10 +209,7 @@ If the error persists, please check whether Actions and API requests are operati
*/ */
async getArtifact( async getArtifact(
artifactName: string, artifactName: string,
workflowRunId: number, options?: LookupOptions
repositoryOwner: string,
repositoryName: string,
token: string
): Promise<GetArtifactResponse> { ): Promise<GetArtifactResponse> {
if (isGhes()) { if (isGhes()) {
warning( warning(
@ -234,13 +221,17 @@ If the error persists, please check whether Actions and API requests are operati
} }
try { try {
return getArtifact( if (options?.token) {
artifactName, return getArtifactPublic(
workflowRunId, artifactName,
repositoryOwner, options.workflowRunId,
repositoryName, options.repositoryOwner,
token options.repositoryName,
) options.token
)
}
return getArtifactInternal(artifactName)
} catch (error: unknown) { } catch (error: unknown) {
warning( warning(
`Fetching Artifact failed with error: ${error}. `Fetching Artifact failed with error: ${error}.

View File

@ -9,6 +9,9 @@ import {
} from '../shared/interfaces' } from '../shared/interfaces'
import {getUserAgentString} from '../shared/user-agent' import {getUserAgentString} from '../shared/user-agent'
import {getGitHubWorkspaceDir} from '../shared/config' import {getGitHubWorkspaceDir} from '../shared/config'
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
import {GetSignedArtifactURLRequest, ListArtifactsRequest} from 'src/generated'
import {getBackendIdsFromToken} from '../shared/util'
const scrubQueryParameters = (url: string): string => { const scrubQueryParameters = (url: string): string => {
const parsed = new URL(url) const parsed = new URL(url)
@ -42,23 +45,14 @@ async function streamExtract(url: string, directory: string): Promise<void> {
return response.message.pipe(unzipper.Extract({path: directory})).promise() return response.message.pipe(unzipper.Extract({path: directory})).promise()
} }
export async function downloadArtifact( export async function downloadArtifactPublic(
artifactId: number, artifactId: number,
repositoryOwner: string, repositoryOwner: string,
repositoryName: string, repositoryName: string,
token: string, token: string,
options?: DownloadArtifactOptions options?: DownloadArtifactOptions
): Promise<DownloadArtifactResponse> { ): Promise<DownloadArtifactResponse> {
const downloadPath = options?.path || getGitHubWorkspaceDir() const downloadPath = await resolveOrCreateDirectory(options?.path)
if (!(await exists(downloadPath))) {
core.debug(
`Artifact destination folder does not exist, creating: ${downloadPath}`
)
await fs.mkdir(downloadPath, {recursive: true})
} else {
core.debug(`Artifact destination folder already exists: ${downloadPath}`)
}
const api = github.getOctokit(token) const api = github.getOctokit(token)
@ -99,3 +93,72 @@ export async function downloadArtifact(
return {success: true, downloadPath} return {success: true, downloadPath}
} }
export async function downloadArtifactInternal(
artifactId: number,
options?: DownloadArtifactOptions
): Promise<DownloadArtifactResponse> {
const downloadPath = await resolveOrCreateDirectory(options?.path)
const artifactClient = internalArtifactTwirpClient()
const {workflowRunBackendId, workflowJobRunBackendId} =
getBackendIdsFromToken()
const listReq: ListArtifactsRequest = {
workflowRunBackendId,
workflowJobRunBackendId,
nameFilter: '',
idFilter: '0' // TODO(robherley): zero values are awkward, use pb wrappers
}
const {artifacts} = await artifactClient.ListArtifacts(listReq)
if (artifacts.length === 0) {
core.warning(
`No artifacts found for ID: ${artifactId}\nAre you trying to download from a different run? Try specifying a github-token with \`actions:read\` scope.`
)
return {success: false}
}
if (artifacts.length > 1) {
core.warning('Multiple artifacts found, defaulting to first.')
}
const signedReq: GetSignedArtifactURLRequest = {
workflowRunBackendId: artifacts[0].workflowRunBackendId,
workflowJobRunBackendId: artifacts[0].workflowJobRunBackendId,
name: artifacts[0].name
}
const {signedUrl} = await artifactClient.GetSignedArtifactURL(signedReq)
core.info(
`Redirecting to blob download url: ${scrubQueryParameters(signedUrl)}`
)
try {
core.info(`Starting download of artifact to: ${downloadPath}`)
await streamExtract(signedUrl, downloadPath)
core.info(`Artifact download completed successfully.`)
} catch (error) {
throw new Error(`Unable to download and extract artifact: ${error.message}`)
}
return {success: true, downloadPath}
}
async function resolveOrCreateDirectory(
downloadPath = getGitHubWorkspaceDir()
): Promise<string> {
if (!(await exists(downloadPath))) {
core.debug(
`Artifact destination folder does not exist, creating: ${downloadPath}`
)
await fs.mkdir(downloadPath, {recursive: true})
} else {
core.debug(`Artifact destination folder already exists: ${downloadPath}`)
}
return downloadPath
}

View File

@ -1,14 +1,17 @@
import {GetArtifactResponse} from '../shared/interfaces'
import {getOctokit} from '@actions/github' import {getOctokit} from '@actions/github'
import {getUserAgentString} from '../shared/user-agent'
import {defaults as defaultGitHubOptions} from '@actions/github/lib/utils'
import {getRetryOptions} from './retry-options'
import {requestLog} from '@octokit/plugin-request-log'
import {retry} from '@octokit/plugin-retry' import {retry} from '@octokit/plugin-retry'
import * as core from '@actions/core' import * as core from '@actions/core'
import {OctokitOptions} from '@octokit/core/dist-types/types' import {OctokitOptions} from '@octokit/core/dist-types/types'
import {defaults as defaultGitHubOptions} from '@actions/github/lib/utils'
import {getRetryOptions} from './retry-options'
import {requestLog} from '@octokit/plugin-request-log'
import {GetArtifactResponse} from '../shared/interfaces'
import {getBackendIdsFromToken} from '../shared/util'
import {getUserAgentString} from '../shared/user-agent'
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
import {ListArtifactsRequest} from '../../generated'
export async function getArtifact( export async function getArtifactPublic(
artifactName: string, artifactName: string,
workflowRunId: number, workflowRunId: number,
repositoryOwner: string, repositoryOwner: string,
@ -62,8 +65,55 @@ export async function getArtifact(
artifact: { artifact: {
name: getArtifactResp.data.artifacts[0].name, name: getArtifactResp.data.artifacts[0].name,
id: getArtifactResp.data.artifacts[0].id, id: getArtifactResp.data.artifacts[0].id,
url: getArtifactResp.data.artifacts[0].url,
size: getArtifactResp.data.artifacts[0].size_in_bytes size: getArtifactResp.data.artifacts[0].size_in_bytes
} }
} }
} }
export async function getArtifactInternal(
artifactName: string
): Promise<GetArtifactResponse> {
const artifactClient = internalArtifactTwirpClient()
const {workflowRunBackendId, workflowJobRunBackendId} =
getBackendIdsFromToken()
const req: ListArtifactsRequest = {
workflowRunBackendId,
workflowJobRunBackendId,
nameFilter: artifactName,
idFilter: '0' // TODO(robherley): int64 zero value, change this to be optional
}
const res = await artifactClient.ListArtifacts(req)
if (res.artifacts.length === 0) {
core.warning('no artifacts found')
return {
success: false
}
}
if (res.artifacts.length > 1) {
core.warning(
'more than one artifact found for a single name, returning first'
)
}
// In the case of reruns, we may have artifacts with the same name scoped under the same workflow run.
// Let's prefer the artifact closest scoped to this run.
// If it doesn't exist (e.g. partial rerun) we'll use the first match.
const artifact =
res.artifacts.find(
artifact => artifact.workflowRunBackendId === workflowRunBackendId
) || res.artifacts[0]
return {
success: true,
artifact: {
name: artifact.name,
id: Number(artifact.databaseId),
size: Number(artifact.size)
}
}
}

View File

@ -7,13 +7,16 @@ import {defaults as defaultGitHubOptions} from '@actions/github/lib/utils'
import {requestLog} from '@octokit/plugin-request-log' import {requestLog} from '@octokit/plugin-request-log'
import {retry} from '@octokit/plugin-retry' import {retry} from '@octokit/plugin-retry'
import {OctokitOptions} from '@octokit/core/dist-types/types' import {OctokitOptions} from '@octokit/core/dist-types/types'
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
import {getBackendIdsFromToken} from '../shared/util'
import {ListArtifactsRequest} from 'src/generated'
// Limiting to 1000 for perf reasons // Limiting to 1000 for perf reasons
const maximumArtifactCount = 1000 const maximumArtifactCount = 1000
const paginationCount = 100 const paginationCount = 100
const maxNumberOfPages = maximumArtifactCount / paginationCount const maxNumberOfPages = maximumArtifactCount / paginationCount
export async function listArtifacts( export async function listArtifactsPublic(
workflowRunId: number, workflowRunId: number,
repositoryOwner: string, repositoryOwner: string,
repositoryName: string, repositoryName: string,
@ -62,7 +65,6 @@ export async function listArtifacts(
artifacts.push({ artifacts.push({
name: artifact.name, name: artifact.name,
id: artifact.id, id: artifact.id,
url: artifact.url,
size: artifact.size_in_bytes size: artifact.size_in_bytes
}) })
} }
@ -89,13 +91,39 @@ export async function listArtifacts(
artifacts.push({ artifacts.push({
name: artifact.name, name: artifact.name,
id: artifact.id, id: artifact.id,
url: artifact.url,
size: artifact.size_in_bytes size: artifact.size_in_bytes
}) })
} }
} }
info(`Finished fetching artifact list`) info(`Found ${artifacts.length} artifact(s)`)
return {
artifacts
}
}
export async function listArtifactsInternal(): Promise<ListArtifactsResponse> {
const artifactClient = internalArtifactTwirpClient()
const {workflowRunBackendId, workflowJobRunBackendId} =
getBackendIdsFromToken()
const req: ListArtifactsRequest = {
workflowRunBackendId,
workflowJobRunBackendId,
nameFilter: '',
idFilter: '0' // TODO(robherley): zero values are awkward, use pb wrappers
}
const res = await artifactClient.ListArtifacts(req)
const artifacts = res.artifacts.map(artifact => ({
name: artifact.name,
id: Number(artifact.databaseId),
size: Number(artifact.size)
}))
info(`Found ${artifacts.length} artifact(s)`)
return { return {
artifacts artifacts

View File

@ -3,6 +3,7 @@ import {BearerCredentialHandler} from '@actions/http-client/lib/auth'
import {info, debug} from '@actions/core' import {info, debug} from '@actions/core'
import {ArtifactServiceClientJSON} from '../../generated' import {ArtifactServiceClientJSON} from '../../generated'
import {getResultsServiceUrl, getRuntimeToken} from './config' import {getResultsServiceUrl, getRuntimeToken} from './config'
import {getUserAgentString} from './user-agent'
// The twirp http client must implement this interface // The twirp http client must implement this interface
interface Rpc { interface Rpc {
@ -157,17 +158,16 @@ class ArtifactHttpClient implements Rpc {
} }
} }
export function createArtifactTwirpClient( export function internalArtifactTwirpClient(options?: {
type: 'upload' | 'download', maxAttempts?: number
maxAttempts?: number, baseRetryIntervalMilliseconds?: number
baseRetryIntervalMilliseconds?: number,
retryMultiplier?: number retryMultiplier?: number
): ArtifactServiceClientJSON { }): ArtifactServiceClientJSON {
const client = new ArtifactHttpClient( const client = new ArtifactHttpClient(
`@actions/artifact-${type}`, getUserAgentString(),
maxAttempts, options?.maxAttempts,
baseRetryIntervalMilliseconds, options?.baseRetryIntervalMilliseconds,
retryMultiplier options?.retryMultiplier
) )
return new ArtifactServiceClientJSON(client) return new ArtifactServiceClientJSON(client)
} }

View File

@ -120,13 +120,21 @@ export interface Artifact {
*/ */
id: number id: number
/**
* The URL of the artifact
*/
url: string
/** /**
* The size of the artifact in bytes * The size of the artifact in bytes
*/ */
size: number size: number
} }
// LookupOptions are for fetching Artifact(s) out of the scope of the current run.
// Must specify a PAT with actions:read scope for cross run/repo lookup otherwise these will be ignored.
export interface LookupOptions {
// Token with actions:read permissions
token: string
// WorkflowRun of the artifact(s) to lookup
workflowRunId: number
// Repository owner
repositoryOwner: string
// Repository name
repositoryName: string
}

View File

@ -1,3 +1,4 @@
import * as core from '@actions/core'
import {getRuntimeToken} from './config' import {getRuntimeToken} from './config'
import jwt_decode from 'jwt-decode' import jwt_decode from 'jwt-decode'
@ -11,7 +12,7 @@ interface ActionsToken {
} }
const InvalidJwtError = new Error( const InvalidJwtError = new Error(
'Failed to get backend IDs: The provided JWT token is invalid' 'Failed to get backend IDs: The provided JWT token is invalid and/or missing claims'
) )
// uses the JWT token claims to get the // uses the JWT token claims to get the
@ -41,24 +42,29 @@ export function getBackendIdsFromToken(): BackendIds {
for (const scopes of scpParts) { for (const scopes of scpParts) {
const scopeParts = scopes.split(':') const scopeParts = scopes.split(':')
if (scopeParts?.[0] !== 'Actions.Results') {
// not the Actions.Results scope
continue
}
/* /*
* example scopeParts: * example scopeParts:
* ["Actions.Results", "ce7f54c7-61c7-4aae-887f-30da475f5f1a", "ca395085-040a-526b-2ce8-bdc85f692774"] * ["Actions.Results", "ce7f54c7-61c7-4aae-887f-30da475f5f1a", "ca395085-040a-526b-2ce8-bdc85f692774"]
*/ */
if (scopeParts.length !== 3) { if (scopeParts.length !== 3) {
// not the Actions.Results scope // missing expected number of claims
continue throw InvalidJwtError
} }
if (scopeParts[0] !== 'Actions.Results') { const ids = {
// not the Actions.Results scope
continue
}
return {
workflowRunBackendId: scopeParts[1], workflowRunBackendId: scopeParts[1],
workflowJobRunBackendId: scopeParts[2] workflowJobRunBackendId: scopeParts[2]
} }
core.debug(`Workflow Run Backend ID: ${ids.workflowRunBackendId}`)
core.debug(`Workflow Job Run Backend ID: ${ids.workflowJobRunBackendId}`)
return ids
} }
throw InvalidJwtError throw InvalidJwtError

View File

@ -2,7 +2,7 @@ import * as core from '@actions/core'
import {UploadOptions, UploadResponse} from '../shared/interfaces' import {UploadOptions, UploadResponse} from '../shared/interfaces'
import {getExpiration} from './retention' import {getExpiration} from './retention'
import {validateArtifactName} from './path-and-artifact-name-validation' import {validateArtifactName} from './path-and-artifact-name-validation'
import {createArtifactTwirpClient} from '../shared/artifact-twirp-client' import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
import { import {
UploadZipSpecification, UploadZipSpecification,
getUploadZipSpecification, getUploadZipSpecification,
@ -44,21 +44,9 @@ export async function uploadArtifact(
// get the IDs needed for the artifact creation // get the IDs needed for the artifact creation
const backendIds = getBackendIdsFromToken() const backendIds = getBackendIdsFromToken()
if (!backendIds.workflowRunBackendId || !backendIds.workflowJobRunBackendId) {
core.warning(
`Failed to get the necessary backend ids which are required to create the artifact`
)
return {
success: false
}
}
core.debug(`Workflow Run Backend ID: ${backendIds.workflowRunBackendId}`)
core.debug(
`Workflow Job Run Backend ID: ${backendIds.workflowJobRunBackendId}`
)
// create the artifact client // create the artifact client
const artifactClient = createArtifactTwirpClient('upload') const artifactClient = internalArtifactTwirpClient()
// create the artifact // create the artifact
const createArtifactReq: CreateArtifactRequest = { const createArtifactReq: CreateArtifactRequest = {