import { Arch, httpExecutor, InvalidConfigurationError, isEmptyOrSpaces, log } from "builder-util"import { configureRequestOptions, HttpExecutor } from "builder-util-runtime"import { BitbucketOptions } from "builder-util-runtime/out/publishOptions"import * as FormData from "form-data"import { readFile } from "fs-extra"import { ClientRequest, RequestOptions } from "http"import { PublishContext } from "./"import { HttpPublisher } from "./httpPublisher"export class BitbucketPublisher extends HttpPublisher {readonly providerName = "bitbucket"readonly hostname = "api.bitbucket.org"private readonly info: BitbucketOptionsprivate readonly auth: stringprivate readonly basePath: stringconstructor(context: PublishContext, info: BitbucketOptions) {super(context)const token = info.token || process.env.BITBUCKET_TOKEN || nullconst username = info.username || process.env.BITBUCKET_USERNAME || nullif (isEmptyOrSpaces(token)) {throw new InvalidConfigurationError(`Bitbucket token is not set using env "BITBUCKET_TOKEN" (see https://www.electron.build/publish#BitbucketOptions)`)}if (isEmptyOrSpaces(username)) {log.warn('No Bitbucket username provided via "BITBUCKET_USERNAME". Defaulting to use repo owner.')}this.info = infothis.auth = BitbucketPublisher.convertAppPassword(username ?? this.info.owner, token)this.basePath = `/2.0/repositories/${this.info.owner}/${this.info.slug}/downloads`}protected doUpload(fileName: string,_arch: Arch,_dataLength: number,_requestProcessor: (request: ClientRequest, reject: (error: Error) => void) => void,file: string): Promise<any> {return HttpExecutor.retryOnServerError(async () => {const fileContent = await readFile(file)const form = new FormData()form.append("files", fileContent, fileName)const upload: RequestOptions = {hostname: this.hostname,path: this.basePath,headers: form.getHeaders(),timeout: this.info.timeout || undefined,}await httpExecutor.doApiRequest(configureRequestOptions(upload, this.auth, "POST"), this.context.cancellationToken, it => form.pipe(it))return fileName})}async deleteRelease(filename: string): Promise<void> {const req: RequestOptions = {hostname: this.hostname,path: `${this.basePath}/${filename}`,timeout: this.info.timeout || undefined,}await httpExecutor.request(configureRequestOptions(req, this.auth, "DELETE"), this.context.cancellationToken)}toString() {const { owner, slug, channel } = this.inforeturn `Bitbucket (owner: ${owner}, slug: ${slug}, channel: ${channel})`}static convertAppPassword(username: string, token: string) {const base64encodedData = Buffer.from(`${username}:${token.trim()}`).toString("base64")return `Basic ${base64encodedData}`}}