flotilla/scripts/release/lib/gitea.mjs

108 lines
3.1 KiB
JavaScript

export const gitea = ({repository, token}) => {
const base = `${repository.origin}/api/v1/repos${repository.pathname}`
const api = async (method, path, {body, allow404} = {}) => {
const multipart = body instanceof FormData
const response = await fetch(base + path, {
method,
headers: {
Authorization: `token ${token}`,
...(body && !multipart ? {"Content-Type": "application/json"} : {}),
},
body: multipart ? body : body && JSON.stringify(body),
})
if (response.status === 404 && allow404) {
return undefined
}
if (!response.ok) {
throw new Error(`${method} ${path} responded ${response.status}: ${await response.text()}`)
}
return response.status === 204 ? undefined : response.json()
}
return {
hasTag: async tag => Boolean(await api("GET", `/tags/${tag}`, {allow404: true})),
latestRelease: () => api("GET", "/releases/latest", {allow404: true}),
upsertRelease: async (tag, notes) =>
(await api("GET", `/releases/tags/${tag}`, {allow404: true})) ??
(await api("POST", "/releases", {
body: {tag_name: tag, name: tag, body: notes, draft: true},
})),
assetNames: async releaseId =>
((await api("GET", `/releases/${releaseId}`)).assets ?? []).map(asset => asset.name),
publish: releaseId => api("PATCH", `/releases/${releaseId}`, {body: {draft: false}}),
attach: async (releaseId, filename, data) => {
const {assets} = await api("GET", `/releases/${releaseId}`)
const existing = assets?.find(asset => asset.name === filename)
if (existing) {
await api("DELETE", `/releases/${releaseId}/assets/${existing.id}`)
}
const form = new FormData()
form.append("attachment", new Blob([data]), filename)
const asset = await api(
"POST",
`/releases/${releaseId}/assets?name=${encodeURIComponent(filename)}`,
{body: form},
)
return asset.browser_download_url
},
}
}
// Gitea's generic package registry, for files that shouldn't sit on the release itself
export const giteaPackage = ({repository, token, name, version}) => {
const [, owner] = repository.pathname.split("/")
const url = file =>
`${repository.origin}/api/packages/${owner}/generic/${name}/${version}/${encodeURIComponent(file)}`
const request = async (method, file, body) => {
const response = await fetch(url(file), {
method,
headers: {Authorization: `token ${token}`},
body,
})
if (response.status === 404 && method !== "PUT") {
return undefined
}
if (!response.ok) {
throw new Error(
`${method} ${url(file)} responded ${response.status}: ${await response.text()}`,
)
}
return response
}
return {
url,
download: async file => {
const response = await request("GET", file)
return response && new Uint8Array(await response.arrayBuffer())
},
// A package file can't be overwritten, so a rebuild of the same version replaces it
upload: async (file, data) => {
await request("DELETE", file)
await request("PUT", file, data)
return url(file)
},
}
}