83 lines
2.7 KiB
JavaScript
83 lines
2.7 KiB
JavaScript
#!/usr/bin/env node
|
|
// Copies gitea's latest published release to the GitHub mirror, whose releases are what Obtainium
|
|
// sees for anyone who added the app by its GitHub url. Run by .gitea/workflows/mirror.yml.
|
|
import {gitea} from "./lib/gitea.mjs"
|
|
import {fail} from "./lib/shell.mjs"
|
|
|
|
const mirror = "coracle-social/flotilla"
|
|
const repository = new URL(`${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}`)
|
|
const token = process.env.GH_MIRROR_TOKEN
|
|
|
|
if (!token || !process.env.GITEA_TOKEN) {
|
|
fail("Set GITEA_TOKEN and GH_MIRROR_TOKEN")
|
|
}
|
|
|
|
const github = async (method, url, {body, allow404} = {}) => {
|
|
const binary = body instanceof Uint8Array
|
|
const response = await fetch(url.startsWith("https://") ? url : `https://api.github.com${url}`, {
|
|
method,
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
Accept: "application/vnd.github+json",
|
|
...(body ? {"Content-Type": binary ? "application/octet-stream" : "application/json"} : {}),
|
|
},
|
|
body: binary ? body : body && JSON.stringify(body),
|
|
})
|
|
|
|
if (response.status === 404 && allow404) {
|
|
return undefined
|
|
}
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`${method} ${url} responded ${response.status}: ${await response.text()}`)
|
|
}
|
|
|
|
return response.status === 204 ? undefined : response.json()
|
|
}
|
|
|
|
const source = await gitea({repository, token: process.env.GITEA_TOKEN}).latestRelease()
|
|
|
|
if (!source) {
|
|
console.log("gitea has no published release")
|
|
process.exit(0)
|
|
}
|
|
|
|
const tag = source.tag_name
|
|
|
|
// Creating a release for a tag GitHub doesn't have yet would tag its default branch instead
|
|
if (!(await github("GET", `/repos/${mirror}/git/ref/tags/${tag}`, {allow404: true}))) {
|
|
fail(`${mirror} has no ${tag} tag yet; the mirror job pushes it`)
|
|
}
|
|
|
|
const release =
|
|
(await github("GET", `/repos/${mirror}/releases/tags/${tag}`, {allow404: true})) ??
|
|
(await github("POST", `/repos/${mirror}/releases`, {
|
|
body: {tag_name: tag, name: source.name, body: source.body, make_latest: "true"},
|
|
}))
|
|
|
|
for (const asset of source.assets) {
|
|
const existing = release.assets.find(({name}) => name === asset.name)
|
|
|
|
// A moved tag rebuilds its assets under the same names, which only the size gives away
|
|
if (existing?.size === asset.size) {
|
|
continue
|
|
}
|
|
|
|
if (existing) {
|
|
await github("DELETE", `/repos/${mirror}/releases/assets/${existing.id}`)
|
|
}
|
|
|
|
const response = await fetch(asset.browser_download_url)
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Downloading ${asset.name} responded ${response.status}`)
|
|
}
|
|
|
|
await github(
|
|
"POST",
|
|
`https://uploads.github.com/repos/${mirror}/releases/${release.id}/assets?name=${encodeURIComponent(asset.name)}`,
|
|
{body: new Uint8Array(await response.arrayBuffer())},
|
|
)
|
|
|
|
console.log(`${tag}: ${asset.name}`)
|
|
}
|