Copy gitea's latest release to the GitHub mirror so Obtainium users on the GitHub url get updates
This commit is contained in:
parent
6ae38287cb
commit
e8bd6acc32
3 changed files with 111 additions and 1 deletions
|
|
@ -4,6 +4,10 @@ on:
|
|||
push:
|
||||
branches: [master]
|
||||
tags: ["*"]
|
||||
# A release goes public whenever its last artifact lands, which can be from a local run hours
|
||||
# after the tag, so its copy on GitHub is kept up to date by polling
|
||||
schedule:
|
||||
- cron: "*/30 * * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
# Serialized rather than cancel-in-progress: aborting a push halfway leaves the
|
||||
|
|
@ -14,7 +18,7 @@ concurrency:
|
|||
jobs:
|
||||
push-to-github:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'coracle/flotilla'
|
||||
if: github.repository == 'coracle/flotilla' && github.event_name != 'schedule'
|
||||
|
||||
steps:
|
||||
- name: Push master and tags to GitHub
|
||||
|
|
@ -32,3 +36,24 @@ jobs:
|
|||
"https://x-access-token:$GH_MIRROR_TOKEN@github.com/coracle-social/flotilla.git" \
|
||||
'refs/heads/master:refs/heads/master' \
|
||||
'refs/tags/*:refs/tags/*'
|
||||
|
||||
# Obtainium reads releases from whichever url a user added, and many added the GitHub one
|
||||
copy-release-to-github:
|
||||
runs-on: ubuntu-latest
|
||||
needs: push-to-github
|
||||
if: ${{ !cancelled() && github.repository == 'coracle/flotilla' && needs.push-to-github.result != 'failure' }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
|
||||
- name: Copy gitea's latest release to GitHub
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_MIRROR_TOKEN: ${{ secrets.GH_MIRROR_TOKEN }}
|
||||
run: node scripts/release/github.mjs
|
||||
|
|
|
|||
83
scripts/release/github.mjs
Normal file
83
scripts/release/github.mjs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#!/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}`)
|
||||
}
|
||||
|
|
@ -26,6 +26,8 @@ export const gitea = ({repository, token}) => {
|
|||
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", {
|
||||
|
|
|
|||
Loading…
Reference in a new issue