mirror of https://github.com/actions/toolkit
add public and internal methods to delete artifacts
parent
1b5a6e26f4
commit
b62d4c91b6
|
@ -0,0 +1,170 @@
|
||||||
|
import * as github from '@actions/github'
|
||||||
|
import type {RestEndpointMethods} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/method-types'
|
||||||
|
import type {RequestInterface} from '@octokit/types'
|
||||||
|
import {
|
||||||
|
deleteArtifactInternal,
|
||||||
|
deleteArtifactPublic
|
||||||
|
} from '../src/internal/delete/delete-artifact'
|
||||||
|
import * as config from '../src/internal/shared/config'
|
||||||
|
import {ArtifactServiceClientJSON} from '../src/generated'
|
||||||
|
import * as util from '../src/internal/shared/util'
|
||||||
|
import {noopLogs} from './common'
|
||||||
|
|
||||||
|
type MockedRequest = jest.MockedFunction<RequestInterface<object>>
|
||||||
|
|
||||||
|
type MockedDeleteArtifact = jest.MockedFunction<
|
||||||
|
RestEndpointMethods['actions']['deleteArtifact']
|
||||||
|
>
|
||||||
|
|
||||||
|
jest.mock('@actions/github', () => ({
|
||||||
|
getOctokit: jest.fn().mockReturnValue({
|
||||||
|
request: jest.fn(),
|
||||||
|
rest: {
|
||||||
|
actions: {
|
||||||
|
deleteArtifact: jest.fn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
|
||||||
|
const fixtures = {
|
||||||
|
repo: 'toolkit',
|
||||||
|
owner: 'actions',
|
||||||
|
token: 'ghp_1234567890',
|
||||||
|
runId: 123,
|
||||||
|
backendIds: {
|
||||||
|
workflowRunBackendId: 'c4d7c21f-ba3f-4ddc-a8c8-6f2f626f8422',
|
||||||
|
workflowJobRunBackendId: '760803a1-f890-4d25-9a6e-a3fc01a0c7cf'
|
||||||
|
},
|
||||||
|
artifacts: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'my-artifact',
|
||||||
|
size: 456,
|
||||||
|
createdAt: new Date('2023-12-01')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'my-artifact',
|
||||||
|
size: 456,
|
||||||
|
createdAt: new Date('2023-12-02')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('delete-artifact', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
noopLogs()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('public', () => {
|
||||||
|
it('should delete an artifact', async () => {
|
||||||
|
const mockRequest = github.getOctokit(fixtures.token)
|
||||||
|
.request as MockedRequest
|
||||||
|
mockRequest.mockResolvedValueOnce({
|
||||||
|
status: 200,
|
||||||
|
headers: {},
|
||||||
|
url: '',
|
||||||
|
data: {
|
||||||
|
artifacts: [
|
||||||
|
{
|
||||||
|
name: fixtures.artifacts[0].name,
|
||||||
|
id: fixtures.artifacts[0].id,
|
||||||
|
size_in_bytes: fixtures.artifacts[0].size,
|
||||||
|
created_at: fixtures.artifacts[0].createdAt.toISOString()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const mockDeleteArtifact = github.getOctokit(fixtures.token).rest.actions
|
||||||
|
.deleteArtifact as MockedDeleteArtifact
|
||||||
|
mockDeleteArtifact.mockResolvedValueOnce({
|
||||||
|
status: 204,
|
||||||
|
headers: {},
|
||||||
|
url: '',
|
||||||
|
data: null as never
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await deleteArtifactPublic(
|
||||||
|
fixtures.artifacts[0].name,
|
||||||
|
fixtures.runId,
|
||||||
|
fixtures.owner,
|
||||||
|
fixtures.repo,
|
||||||
|
fixtures.token
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response).toEqual({
|
||||||
|
id: fixtures.artifacts[0].id
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fail if non-200 response', async () => {
|
||||||
|
const mockRequest = github.getOctokit(fixtures.token)
|
||||||
|
.request as MockedRequest
|
||||||
|
mockRequest.mockResolvedValueOnce({
|
||||||
|
status: 200,
|
||||||
|
headers: {},
|
||||||
|
url: '',
|
||||||
|
data: {
|
||||||
|
artifacts: [
|
||||||
|
{
|
||||||
|
name: fixtures.artifacts[0].name,
|
||||||
|
id: fixtures.artifacts[0].id,
|
||||||
|
size_in_bytes: fixtures.artifacts[0].size,
|
||||||
|
created_at: fixtures.artifacts[0].createdAt.toISOString()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const mockDeleteArtifact = github.getOctokit(fixtures.token).rest.actions
|
||||||
|
.deleteArtifact as MockedDeleteArtifact
|
||||||
|
mockDeleteArtifact.mockRejectedValue(new Error('boom'))
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
deleteArtifactPublic(
|
||||||
|
fixtures.artifacts[0].name,
|
||||||
|
fixtures.runId,
|
||||||
|
fixtures.owner,
|
||||||
|
fixtures.repo,
|
||||||
|
fixtures.token
|
||||||
|
)
|
||||||
|
).rejects.toThrow('boom')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('internal', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
|
||||||
|
jest
|
||||||
|
.spyOn(util, 'getBackendIdsFromToken')
|
||||||
|
.mockReturnValue(fixtures.backendIds)
|
||||||
|
jest
|
||||||
|
.spyOn(config, 'getResultsServiceUrl')
|
||||||
|
.mockReturnValue('https://results.local')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return a list of artifacts', async () => {
|
||||||
|
jest
|
||||||
|
.spyOn(ArtifactServiceClientJSON.prototype, 'DeleteArtifact')
|
||||||
|
.mockResolvedValue({
|
||||||
|
ok: true,
|
||||||
|
artifactId: fixtures.artifacts[0].id.toString()
|
||||||
|
})
|
||||||
|
const response = await deleteArtifactInternal(fixtures.artifacts[0].name)
|
||||||
|
expect(response).toEqual({
|
||||||
|
id: fixtures.artifacts[0].id
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fail if non-200 response', async () => {
|
||||||
|
jest
|
||||||
|
.spyOn(ArtifactServiceClientJSON.prototype, 'DeleteArtifact')
|
||||||
|
.mockRejectedValue(new Error('boom'))
|
||||||
|
await expect(
|
||||||
|
deleteArtifactInternal(fixtures.artifacts[0].id)
|
||||||
|
).rejects.toThrow('boom')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -196,6 +196,36 @@ export interface GetSignedArtifactURLResponse {
|
||||||
*/
|
*/
|
||||||
signedUrl: string;
|
signedUrl: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @generated from protobuf message github.actions.results.api.v1.DeleteArtifactRequest
|
||||||
|
*/
|
||||||
|
export interface DeleteArtifactRequest {
|
||||||
|
/**
|
||||||
|
* @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.DeleteArtifactResponse
|
||||||
|
*/
|
||||||
|
export interface DeleteArtifactResponse {
|
||||||
|
/**
|
||||||
|
* @generated from protobuf field: bool ok = 1;
|
||||||
|
*/
|
||||||
|
ok: boolean;
|
||||||
|
/**
|
||||||
|
* @generated from protobuf field: int64 artifact_id = 2;
|
||||||
|
*/
|
||||||
|
artifactId: 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() {
|
||||||
|
@ -759,6 +789,121 @@ class GetSignedArtifactURLResponse$Type extends MessageType<GetSignedArtifactURL
|
||||||
* @generated MessageType for protobuf message github.actions.results.api.v1.GetSignedArtifactURLResponse
|
* @generated MessageType for protobuf message github.actions.results.api.v1.GetSignedArtifactURLResponse
|
||||||
*/
|
*/
|
||||||
export const GetSignedArtifactURLResponse = new GetSignedArtifactURLResponse$Type();
|
export const GetSignedArtifactURLResponse = new GetSignedArtifactURLResponse$Type();
|
||||||
|
// @generated message type with reflection information, may provide speed optimized methods
|
||||||
|
class DeleteArtifactRequest$Type extends MessageType<DeleteArtifactRequest> {
|
||||||
|
constructor() {
|
||||||
|
super("github.actions.results.api.v1.DeleteArtifactRequest", [
|
||||||
|
{ 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<DeleteArtifactRequest>): DeleteArtifactRequest {
|
||||||
|
const message = { workflowRunBackendId: "", workflowJobRunBackendId: "", name: "" };
|
||||||
|
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||||
|
if (value !== undefined)
|
||||||
|
reflectionMergePartial<DeleteArtifactRequest>(this, message, value);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeleteArtifactRequest): DeleteArtifactRequest {
|
||||||
|
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: DeleteArtifactRequest, 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.DeleteArtifactRequest
|
||||||
|
*/
|
||||||
|
export const DeleteArtifactRequest = new DeleteArtifactRequest$Type();
|
||||||
|
// @generated message type with reflection information, may provide speed optimized methods
|
||||||
|
class DeleteArtifactResponse$Type extends MessageType<DeleteArtifactResponse> {
|
||||||
|
constructor() {
|
||||||
|
super("github.actions.results.api.v1.DeleteArtifactResponse", [
|
||||||
|
{ no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
||||||
|
{ no: 2, name: "artifact_id", kind: "scalar", T: 3 /*ScalarType.INT64*/ }
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
create(value?: PartialMessage<DeleteArtifactResponse>): DeleteArtifactResponse {
|
||||||
|
const message = { ok: false, artifactId: "0" };
|
||||||
|
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||||
|
if (value !== undefined)
|
||||||
|
reflectionMergePartial<DeleteArtifactResponse>(this, message, value);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeleteArtifactResponse): DeleteArtifactResponse {
|
||||||
|
let message = target ?? this.create(), end = reader.pos + length;
|
||||||
|
while (reader.pos < end) {
|
||||||
|
let [fieldNo, wireType] = reader.tag();
|
||||||
|
switch (fieldNo) {
|
||||||
|
case /* bool ok */ 1:
|
||||||
|
message.ok = reader.bool();
|
||||||
|
break;
|
||||||
|
case /* int64 artifact_id */ 2:
|
||||||
|
message.artifactId = 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: DeleteArtifactResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||||
|
/* bool ok = 1; */
|
||||||
|
if (message.ok !== false)
|
||||||
|
writer.tag(1, WireType.Varint).bool(message.ok);
|
||||||
|
/* int64 artifact_id = 2; */
|
||||||
|
if (message.artifactId !== "0")
|
||||||
|
writer.tag(2, WireType.Varint).int64(message.artifactId);
|
||||||
|
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.DeleteArtifactResponse
|
||||||
|
*/
|
||||||
|
export const DeleteArtifactResponse = new DeleteArtifactResponse$Type();
|
||||||
/**
|
/**
|
||||||
* @generated ServiceType for protobuf service github.actions.results.api.v1.ArtifactService
|
* @generated ServiceType for protobuf service github.actions.results.api.v1.ArtifactService
|
||||||
*/
|
*/
|
||||||
|
@ -766,5 +911,6 @@ export const ArtifactService = new ServiceType("github.actions.results.api.v1.Ar
|
||||||
{ 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: "ListArtifacts", options: {}, I: ListArtifactsRequest, O: ListArtifactsResponse },
|
||||||
{ name: "GetSignedArtifactURL", options: {}, I: GetSignedArtifactURLRequest, O: GetSignedArtifactURLResponse }
|
{ name: "GetSignedArtifactURL", options: {}, I: GetSignedArtifactURLRequest, O: GetSignedArtifactURLResponse },
|
||||||
|
{ name: "DeleteArtifact", options: {}, I: DeleteArtifactRequest, O: DeleteArtifactResponse }
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -17,6 +17,8 @@ import {
|
||||||
ListArtifactsResponse,
|
ListArtifactsResponse,
|
||||||
GetSignedArtifactURLRequest,
|
GetSignedArtifactURLRequest,
|
||||||
GetSignedArtifactURLResponse,
|
GetSignedArtifactURLResponse,
|
||||||
|
DeleteArtifactRequest,
|
||||||
|
DeleteArtifactResponse,
|
||||||
} from "./artifact";
|
} from "./artifact";
|
||||||
|
|
||||||
//==================================//
|
//==================================//
|
||||||
|
@ -43,6 +45,9 @@ export interface ArtifactServiceClient {
|
||||||
GetSignedArtifactURL(
|
GetSignedArtifactURL(
|
||||||
request: GetSignedArtifactURLRequest
|
request: GetSignedArtifactURLRequest
|
||||||
): Promise<GetSignedArtifactURLResponse>;
|
): Promise<GetSignedArtifactURLResponse>;
|
||||||
|
DeleteArtifact(
|
||||||
|
request: DeleteArtifactRequest
|
||||||
|
): Promise<DeleteArtifactResponse>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ArtifactServiceClientJSON implements ArtifactServiceClient {
|
export class ArtifactServiceClientJSON implements ArtifactServiceClient {
|
||||||
|
@ -53,6 +58,7 @@ export class ArtifactServiceClientJSON implements ArtifactServiceClient {
|
||||||
this.FinalizeArtifact.bind(this);
|
this.FinalizeArtifact.bind(this);
|
||||||
this.ListArtifacts.bind(this);
|
this.ListArtifacts.bind(this);
|
||||||
this.GetSignedArtifactURL.bind(this);
|
this.GetSignedArtifactURL.bind(this);
|
||||||
|
this.DeleteArtifact.bind(this);
|
||||||
}
|
}
|
||||||
CreateArtifact(
|
CreateArtifact(
|
||||||
request: CreateArtifactRequest
|
request: CreateArtifactRequest
|
||||||
|
@ -129,6 +135,26 @@ export class ArtifactServiceClientJSON implements ArtifactServiceClient {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeleteArtifact(
|
||||||
|
request: DeleteArtifactRequest
|
||||||
|
): Promise<DeleteArtifactResponse> {
|
||||||
|
const data = DeleteArtifactRequest.toJson(request, {
|
||||||
|
useProtoFieldName: true,
|
||||||
|
emitDefaultValues: false,
|
||||||
|
});
|
||||||
|
const promise = this.rpc.request(
|
||||||
|
"github.actions.results.api.v1.ArtifactService",
|
||||||
|
"DeleteArtifact",
|
||||||
|
"application/json",
|
||||||
|
data as object
|
||||||
|
);
|
||||||
|
return promise.then((data) =>
|
||||||
|
DeleteArtifactResponse.fromJson(data as any, {
|
||||||
|
ignoreUnknownFields: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ArtifactServiceClientProtobuf implements ArtifactServiceClient {
|
export class ArtifactServiceClientProtobuf implements ArtifactServiceClient {
|
||||||
|
@ -139,6 +165,7 @@ export class ArtifactServiceClientProtobuf implements ArtifactServiceClient {
|
||||||
this.FinalizeArtifact.bind(this);
|
this.FinalizeArtifact.bind(this);
|
||||||
this.ListArtifacts.bind(this);
|
this.ListArtifacts.bind(this);
|
||||||
this.GetSignedArtifactURL.bind(this);
|
this.GetSignedArtifactURL.bind(this);
|
||||||
|
this.DeleteArtifact.bind(this);
|
||||||
}
|
}
|
||||||
CreateArtifact(
|
CreateArtifact(
|
||||||
request: CreateArtifactRequest
|
request: CreateArtifactRequest
|
||||||
|
@ -197,6 +224,21 @@ export class ArtifactServiceClientProtobuf implements ArtifactServiceClient {
|
||||||
GetSignedArtifactURLResponse.fromBinary(data as Uint8Array)
|
GetSignedArtifactURLResponse.fromBinary(data as Uint8Array)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeleteArtifact(
|
||||||
|
request: DeleteArtifactRequest
|
||||||
|
): Promise<DeleteArtifactResponse> {
|
||||||
|
const data = DeleteArtifactRequest.toBinary(request);
|
||||||
|
const promise = this.rpc.request(
|
||||||
|
"github.actions.results.api.v1.ArtifactService",
|
||||||
|
"DeleteArtifact",
|
||||||
|
"application/protobuf",
|
||||||
|
data
|
||||||
|
);
|
||||||
|
return promise.then((data) =>
|
||||||
|
DeleteArtifactResponse.fromBinary(data as Uint8Array)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================//
|
//==================================//
|
||||||
|
@ -220,6 +262,10 @@ export interface ArtifactServiceTwirp<T extends TwirpContext = TwirpContext> {
|
||||||
ctx: T,
|
ctx: T,
|
||||||
request: GetSignedArtifactURLRequest
|
request: GetSignedArtifactURLRequest
|
||||||
): Promise<GetSignedArtifactURLResponse>;
|
): Promise<GetSignedArtifactURLResponse>;
|
||||||
|
DeleteArtifact(
|
||||||
|
ctx: T,
|
||||||
|
request: DeleteArtifactRequest
|
||||||
|
): Promise<DeleteArtifactResponse>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ArtifactServiceMethod {
|
export enum ArtifactServiceMethod {
|
||||||
|
@ -227,6 +273,7 @@ export enum ArtifactServiceMethod {
|
||||||
FinalizeArtifact = "FinalizeArtifact",
|
FinalizeArtifact = "FinalizeArtifact",
|
||||||
ListArtifacts = "ListArtifacts",
|
ListArtifacts = "ListArtifacts",
|
||||||
GetSignedArtifactURL = "GetSignedArtifactURL",
|
GetSignedArtifactURL = "GetSignedArtifactURL",
|
||||||
|
DeleteArtifact = "DeleteArtifact",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ArtifactServiceMethodList = [
|
export const ArtifactServiceMethodList = [
|
||||||
|
@ -234,6 +281,7 @@ export const ArtifactServiceMethodList = [
|
||||||
ArtifactServiceMethod.FinalizeArtifact,
|
ArtifactServiceMethod.FinalizeArtifact,
|
||||||
ArtifactServiceMethod.ListArtifacts,
|
ArtifactServiceMethod.ListArtifacts,
|
||||||
ArtifactServiceMethod.GetSignedArtifactURL,
|
ArtifactServiceMethod.GetSignedArtifactURL,
|
||||||
|
ArtifactServiceMethod.DeleteArtifact,
|
||||||
];
|
];
|
||||||
|
|
||||||
export function createArtifactServiceServer<
|
export function createArtifactServiceServer<
|
||||||
|
@ -333,6 +381,26 @@ function matchArtifactServiceRoute<T extends TwirpContext = TwirpContext>(
|
||||||
interceptors
|
interceptors
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
case "DeleteArtifact":
|
||||||
|
return async (
|
||||||
|
ctx: T,
|
||||||
|
service: ArtifactServiceTwirp,
|
||||||
|
data: Buffer,
|
||||||
|
interceptors?: Interceptor<
|
||||||
|
T,
|
||||||
|
DeleteArtifactRequest,
|
||||||
|
DeleteArtifactResponse
|
||||||
|
>[]
|
||||||
|
) => {
|
||||||
|
ctx = { ...ctx, methodName: "DeleteArtifact" };
|
||||||
|
await events.onMatch(ctx);
|
||||||
|
return handleArtifactServiceDeleteArtifactRequest(
|
||||||
|
ctx,
|
||||||
|
service,
|
||||||
|
data,
|
||||||
|
interceptors
|
||||||
|
);
|
||||||
|
};
|
||||||
default:
|
default:
|
||||||
events.onNotFound();
|
events.onNotFound();
|
||||||
const msg = `no handler found`;
|
const msg = `no handler found`;
|
||||||
|
@ -463,6 +531,35 @@ function handleArtifactServiceGetSignedArtifactURLRequest<
|
||||||
throw new TwirpError(TwirpErrorCode.BadRoute, msg);
|
throw new TwirpError(TwirpErrorCode.BadRoute, msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleArtifactServiceDeleteArtifactRequest<
|
||||||
|
T extends TwirpContext = TwirpContext
|
||||||
|
>(
|
||||||
|
ctx: T,
|
||||||
|
service: ArtifactServiceTwirp,
|
||||||
|
data: Buffer,
|
||||||
|
interceptors?: Interceptor<T, DeleteArtifactRequest, DeleteArtifactResponse>[]
|
||||||
|
): Promise<string | Uint8Array> {
|
||||||
|
switch (ctx.contentType) {
|
||||||
|
case TwirpContentType.JSON:
|
||||||
|
return handleArtifactServiceDeleteArtifactJSON<T>(
|
||||||
|
ctx,
|
||||||
|
service,
|
||||||
|
data,
|
||||||
|
interceptors
|
||||||
|
);
|
||||||
|
case TwirpContentType.Protobuf:
|
||||||
|
return handleArtifactServiceDeleteArtifactProtobuf<T>(
|
||||||
|
ctx,
|
||||||
|
service,
|
||||||
|
data,
|
||||||
|
interceptors
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
const msg = "unexpected Content-Type";
|
||||||
|
throw new TwirpError(TwirpErrorCode.BadRoute, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
async function handleArtifactServiceCreateArtifactJSON<
|
async function handleArtifactServiceCreateArtifactJSON<
|
||||||
T extends TwirpContext = TwirpContext
|
T extends TwirpContext = TwirpContext
|
||||||
>(
|
>(
|
||||||
|
@ -646,6 +743,50 @@ async function handleArtifactServiceGetSignedArtifactURLJSON<
|
||||||
}) as string
|
}) as string
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleArtifactServiceDeleteArtifactJSON<
|
||||||
|
T extends TwirpContext = TwirpContext
|
||||||
|
>(
|
||||||
|
ctx: T,
|
||||||
|
service: ArtifactServiceTwirp,
|
||||||
|
data: Buffer,
|
||||||
|
interceptors?: Interceptor<T, DeleteArtifactRequest, DeleteArtifactResponse>[]
|
||||||
|
) {
|
||||||
|
let request: DeleteArtifactRequest;
|
||||||
|
let response: DeleteArtifactResponse;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const body = JSON.parse(data.toString() || "{}");
|
||||||
|
request = DeleteArtifactRequest.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,
|
||||||
|
DeleteArtifactRequest,
|
||||||
|
DeleteArtifactResponse
|
||||||
|
>;
|
||||||
|
response = await interceptor(ctx, request!, (ctx, inputReq) => {
|
||||||
|
return service.DeleteArtifact(ctx, inputReq);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
response = await service.DeleteArtifact(ctx, request!);
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.stringify(
|
||||||
|
DeleteArtifactResponse.toJson(response, {
|
||||||
|
useProtoFieldName: true,
|
||||||
|
emitDefaultValues: false,
|
||||||
|
}) as string
|
||||||
|
);
|
||||||
|
}
|
||||||
async function handleArtifactServiceCreateArtifactProtobuf<
|
async function handleArtifactServiceCreateArtifactProtobuf<
|
||||||
T extends TwirpContext = TwirpContext
|
T extends TwirpContext = TwirpContext
|
||||||
>(
|
>(
|
||||||
|
@ -797,3 +938,39 @@ async function handleArtifactServiceGetSignedArtifactURLProtobuf<
|
||||||
|
|
||||||
return Buffer.from(GetSignedArtifactURLResponse.toBinary(response));
|
return Buffer.from(GetSignedArtifactURLResponse.toBinary(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleArtifactServiceDeleteArtifactProtobuf<
|
||||||
|
T extends TwirpContext = TwirpContext
|
||||||
|
>(
|
||||||
|
ctx: T,
|
||||||
|
service: ArtifactServiceTwirp,
|
||||||
|
data: Buffer,
|
||||||
|
interceptors?: Interceptor<T, DeleteArtifactRequest, DeleteArtifactResponse>[]
|
||||||
|
) {
|
||||||
|
let request: DeleteArtifactRequest;
|
||||||
|
let response: DeleteArtifactResponse;
|
||||||
|
|
||||||
|
try {
|
||||||
|
request = DeleteArtifactRequest.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,
|
||||||
|
DeleteArtifactRequest,
|
||||||
|
DeleteArtifactResponse
|
||||||
|
>;
|
||||||
|
response = await interceptor(ctx, request!, (ctx, inputReq) => {
|
||||||
|
return service.DeleteArtifact(ctx, inputReq);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
response = await service.DeleteArtifact(ctx, request!);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Buffer.from(DeleteArtifactResponse.toBinary(response));
|
||||||
|
}
|
||||||
|
|
|
@ -8,13 +8,18 @@ import {
|
||||||
ListArtifactsOptions,
|
ListArtifactsOptions,
|
||||||
ListArtifactsResponse,
|
ListArtifactsResponse,
|
||||||
DownloadArtifactResponse,
|
DownloadArtifactResponse,
|
||||||
FindOptions
|
FindOptions,
|
||||||
|
DeleteArtifactResponse
|
||||||
} from './shared/interfaces'
|
} from './shared/interfaces'
|
||||||
import {uploadArtifact} from './upload/upload-artifact'
|
import {uploadArtifact} from './upload/upload-artifact'
|
||||||
import {
|
import {
|
||||||
downloadArtifactPublic,
|
downloadArtifactPublic,
|
||||||
downloadArtifactInternal
|
downloadArtifactInternal
|
||||||
} from './download/download-artifact'
|
} from './download/download-artifact'
|
||||||
|
import {
|
||||||
|
deleteArtifactPublic,
|
||||||
|
deleteArtifactInternal
|
||||||
|
} from './delete/delete-artifact'
|
||||||
import {getArtifactPublic, getArtifactInternal} from './find/get-artifact'
|
import {getArtifactPublic, getArtifactInternal} from './find/get-artifact'
|
||||||
import {listArtifactsPublic, listArtifactsInternal} from './find/list-artifacts'
|
import {listArtifactsPublic, listArtifactsInternal} from './find/list-artifacts'
|
||||||
import {GHESNotSupportedError} from './shared/errors'
|
import {GHESNotSupportedError} from './shared/errors'
|
||||||
|
@ -77,7 +82,7 @@ export interface ArtifactClient {
|
||||||
*
|
*
|
||||||
* If `options.findBy` 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
|
* If `options.findBy` 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 id of the artifact to download
|
||||||
* @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
|
||||||
*/
|
*/
|
||||||
|
@ -85,6 +90,20 @@ export interface ArtifactClient {
|
||||||
artifactId: number,
|
artifactId: number,
|
||||||
options?: DownloadArtifactOptions & FindOptions
|
options?: DownloadArtifactOptions & FindOptions
|
||||||
): Promise<DownloadArtifactResponse>
|
): Promise<DownloadArtifactResponse>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an Artifact
|
||||||
|
*
|
||||||
|
* If `options.findBy` is specified, this will use the public Download Artifact API https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#delete-an-artifact
|
||||||
|
*
|
||||||
|
* @param artifactName The name of the artifact to delete
|
||||||
|
* @param options Extra options that allow for the customization of the delete behavior
|
||||||
|
* @returns single DeleteArtifactResponse object
|
||||||
|
*/
|
||||||
|
deleteArtifact(
|
||||||
|
artifactName: string,
|
||||||
|
options?: FindOptions
|
||||||
|
): Promise<DeleteArtifactResponse>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -225,4 +244,41 @@ If the error persists, please check whether Actions and API requests are operati
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteArtifact(
|
||||||
|
artifactName: string,
|
||||||
|
options?: FindOptions
|
||||||
|
): Promise<DeleteArtifactResponse> {
|
||||||
|
try {
|
||||||
|
if (isGhes()) {
|
||||||
|
throw new GHESNotSupportedError()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options?.findBy) {
|
||||||
|
const {
|
||||||
|
findBy: {repositoryOwner, repositoryName, workflowRunId, token}
|
||||||
|
} = options
|
||||||
|
|
||||||
|
return deleteArtifactPublic(
|
||||||
|
artifactName,
|
||||||
|
workflowRunId,
|
||||||
|
repositoryOwner,
|
||||||
|
repositoryName,
|
||||||
|
token
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return deleteArtifactInternal(artifactName)
|
||||||
|
} catch (error) {
|
||||||
|
warning(
|
||||||
|
`Delete Artifact failed with error: ${error}.
|
||||||
|
|
||||||
|
Errors can be temporary, so please try again and optionally run the action with debug mode enabled for more information.
|
||||||
|
|
||||||
|
If the error persists, please check whether Actions and API requests are operating normally at [https://githubstatus.com](https://www.githubstatus.com).`
|
||||||
|
)
|
||||||
|
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
import {info} from '@actions/core'
|
||||||
|
import {getOctokit} from '@actions/github'
|
||||||
|
import {DeleteArtifactResponse} from '../shared/interfaces'
|
||||||
|
import {getUserAgentString} from '../shared/user-agent'
|
||||||
|
import {getRetryOptions} from '../find/retry-options'
|
||||||
|
import {defaults as defaultGitHubOptions} from '@actions/github/lib/utils'
|
||||||
|
import {requestLog} from '@octokit/plugin-request-log'
|
||||||
|
import {retry} from '@octokit/plugin-retry'
|
||||||
|
import {OctokitOptions} from '@octokit/core/dist-types/types'
|
||||||
|
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
|
||||||
|
import {getBackendIdsFromToken} from '../shared/util'
|
||||||
|
import {DeleteArtifactRequest} from '../../generated'
|
||||||
|
import {getArtifactPublic} from '../find/get-artifact'
|
||||||
|
import {InvalidResponseError} from '../shared/errors'
|
||||||
|
|
||||||
|
export async function deleteArtifactPublic(
|
||||||
|
artifactName: string,
|
||||||
|
workflowRunId: number,
|
||||||
|
repositoryOwner: string,
|
||||||
|
repositoryName: string,
|
||||||
|
token: string
|
||||||
|
): Promise<DeleteArtifactResponse> {
|
||||||
|
const [retryOpts, requestOpts] = getRetryOptions(defaultGitHubOptions)
|
||||||
|
|
||||||
|
const opts: OctokitOptions = {
|
||||||
|
log: undefined,
|
||||||
|
userAgent: getUserAgentString(),
|
||||||
|
previews: undefined,
|
||||||
|
retry: retryOpts,
|
||||||
|
request: requestOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
const github = getOctokit(token, opts, retry, requestLog)
|
||||||
|
|
||||||
|
const getArtifactResp = await getArtifactPublic(
|
||||||
|
artifactName,
|
||||||
|
workflowRunId,
|
||||||
|
repositoryOwner,
|
||||||
|
repositoryName,
|
||||||
|
token
|
||||||
|
)
|
||||||
|
|
||||||
|
const deleteArtifactResp = await github.rest.actions.deleteArtifact({
|
||||||
|
owner: repositoryOwner,
|
||||||
|
repo: repositoryName,
|
||||||
|
artifact_id: getArtifactResp.artifact.id
|
||||||
|
})
|
||||||
|
|
||||||
|
if (deleteArtifactResp.status !== 204) {
|
||||||
|
throw new InvalidResponseError(
|
||||||
|
`Invalid response from GitHub API: ${deleteArtifactResp.status} (${deleteArtifactResp?.headers?.['x-github-request-id']})`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: getArtifactResp.artifact.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteArtifactInternal(
|
||||||
|
artifactName
|
||||||
|
): Promise<DeleteArtifactResponse> {
|
||||||
|
const artifactClient = internalArtifactTwirpClient()
|
||||||
|
|
||||||
|
const {workflowRunBackendId, workflowJobRunBackendId} =
|
||||||
|
getBackendIdsFromToken()
|
||||||
|
|
||||||
|
const req: DeleteArtifactRequest = {
|
||||||
|
workflowRunBackendId,
|
||||||
|
workflowJobRunBackendId,
|
||||||
|
name: artifactName
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await artifactClient.DeleteArtifact(req)
|
||||||
|
info(`Artifact '${artifactName}' (ID: ${res.artifactId}) deleted`)
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: Number(res.artifactId)
|
||||||
|
}
|
||||||
|
}
|
|
@ -147,3 +147,13 @@ export interface FindOptions {
|
||||||
repositoryName: string
|
repositoryName: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response from the server when deleting an artifact
|
||||||
|
*/
|
||||||
|
export interface DeleteArtifactResponse {
|
||||||
|
/**
|
||||||
|
* The id of the artifact that was deleted
|
||||||
|
*/
|
||||||
|
id: number
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue