CI: publish the MSI as a Forgejo release on tags
Some checks failed
CI / Build og unit tests (push) Successful in 13s
CI / MSI-installer (push) Successful in 31s
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Has been cancelled
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Has been cancelled
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Has been cancelled
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Has been cancelled
Some checks failed
CI / Build og unit tests (push) Successful in 13s
CI / MSI-installer (push) Successful in 31s
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Has been cancelled
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Has been cancelled
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Has been cancelled
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Has been cancelled
On a v* tag the msi job creates the release (if missing) and attaches the MSI under its own name and as SQLInsight-Pro-x64.msi, so the newest can be fetched without login from releases/latest/download/. The artifact upload stays for ordinary pushes. Uses the Actions token, or RELEASE_TOKEN if set. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b9afc30436
commit
c91908adce
2 changed files with 80 additions and 0 deletions
|
|
@ -41,6 +41,14 @@ jobs:
|
|||
with:
|
||||
name: SQLInsight-Pro-msi
|
||||
path: dist/*.msi
|
||||
- name: Udgiv som release
|
||||
# Kun tags (v1.2.0): MSI'en vedhæftes releasen og kan hentes uden login fra
|
||||
# <repo>/releases/latest/download/SQLInsight-Pro-x64.msi. RELEASE_TOKEN (valgfri secret) bruges,
|
||||
# hvis Actions' automatiske token ikke må oprette releases.
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
env:
|
||||
TOKEN: ${{ secrets.RELEASE_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
run: python3 installer/publish-release.py dist/*.msi
|
||||
|
||||
integration:
|
||||
name: Integration (${{ matrix.image }})
|
||||
|
|
|
|||
72
installer/publish-release.py
Executable file
72
installer/publish-release.py
Executable file
|
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Attaches the MSI to a Forgejo release for the current tag (created if missing). Run by ci.yml on tags v*.
|
||||
|
||||
publish-release.py dist/SQLInsight-Pro-1.2.0-x64.msi
|
||||
|
||||
Environment (set by Forgejo Actions): GITHUB_SERVER_URL, GITHUB_REPOSITORY, GITHUB_REF_NAME, and TOKEN with write
|
||||
access to the repository. The MSI is attached twice: under its own name and as SQLInsight-Pro-x64.msi, so the
|
||||
newest one can always be fetched from .../releases/latest/download/SQLInsight-Pro-x64.msi.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
import uuid
|
||||
|
||||
LATEST_NAME = "SQLInsight-Pro-x64.msi"
|
||||
|
||||
SERVER = os.environ["GITHUB_SERVER_URL"].rstrip("/")
|
||||
REPO = os.environ["GITHUB_REPOSITORY"]
|
||||
TAG = os.environ["GITHUB_REF_NAME"]
|
||||
TOKEN = os.environ["TOKEN"]
|
||||
API = f"{SERVER}/api/v1/repos/{REPO}"
|
||||
|
||||
|
||||
def call(method, url, body=None, content_type="application/json"):
|
||||
data = json.dumps(body).encode() if isinstance(body, dict) else body
|
||||
request = urllib.request.Request(url, data=data, method=method, headers={
|
||||
"Authorization": f"token {TOKEN}", "Accept": "application/json", "Content-Type": content_type,
|
||||
})
|
||||
try:
|
||||
with urllib.request.urlopen(request, timeout=300) as response:
|
||||
text = response.read().decode()
|
||||
return json.loads(text) if text else {}
|
||||
except urllib.error.HTTPError as error:
|
||||
if error.code == 404 and method == "GET":
|
||||
return None
|
||||
sys.exit(f"{method} {url}: {error.code} {error.read().decode()[:300]}")
|
||||
|
||||
|
||||
def upload(release, path, name):
|
||||
for asset in release.get("assets") or []:
|
||||
if asset["name"] == name: # a re-run of the same tag replaces the file
|
||||
call("DELETE", f"{API}/releases/{release['id']}/assets/{asset['id']}")
|
||||
boundary = uuid.uuid4().hex
|
||||
with open(path, "rb") as f:
|
||||
content = f.read()
|
||||
body = (f"--{boundary}\r\nContent-Disposition: form-data; name=\"attachment\"; filename=\"{name}\"\r\n"
|
||||
f"Content-Type: application/octet-stream\r\n\r\n").encode() + content + f"\r\n--{boundary}--\r\n".encode()
|
||||
call("POST", f"{API}/releases/{release['id']}/assets?name={name}", body, f"multipart/form-data; boundary={boundary}")
|
||||
print(f"vedhæftet {name} ({len(content) // 1024 // 1024} MB)")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
sys.exit(__doc__)
|
||||
msi = sys.argv[1]
|
||||
release = call("GET", f"{API}/releases/tags/{TAG}")
|
||||
if release is None:
|
||||
release = call("POST", f"{API}/releases", {
|
||||
"tag_name": TAG, "name": f"SQLInsight Pro {TAG.removeprefix('v')}",
|
||||
"body": "MSI-installer til Windows (agent og web). Se docs/installation.md.",
|
||||
"draft": False, "prerelease": "-" in TAG,
|
||||
})
|
||||
print(f"release {TAG} oprettet")
|
||||
upload(release, msi, os.path.basename(msi))
|
||||
upload(call("GET", f"{API}/releases/{release['id']}"), msi, LATEST_NAME)
|
||||
print(f"{SERVER}/{REPO}/releases/tag/{TAG}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Add table
Reference in a new issue