Previous approaches using temp files or env vars failed in Gitea runner. Python now runs git commands directly via subprocess, reads stdout, and builds the JSON payload — no intermediate files or shell escaping.
129 lines
3.5 KiB
YAML
129 lines
3.5 KiB
YAML
name: Create Release
|
|
on:
|
|
push:
|
|
tags:
|
|
- "v*"
|
|
jobs:
|
|
release:
|
|
runs-on: shell
|
|
steps:
|
|
- name: Build & release
|
|
env:
|
|
VERSION: ${{ gitea.ref_name }}
|
|
GITEA_API: ${{ gitea.api_url }}
|
|
GITEA_REPO: ${{ gitea.repository }}
|
|
run: |
|
|
set -e
|
|
|
|
LOCAL="/var/www/atom-nexst"
|
|
|
|
# Shallow clone for build
|
|
SRC="/tmp/epicnext-release"
|
|
rm -rf "$SRC"
|
|
git clone --branch "${VERSION}" --depth 1 \
|
|
/docker/gitea/gitea/git/repositories/remco/epicnext-cms.git \
|
|
"$SRC"
|
|
|
|
if [ -f /var/www/atom-nexst/.env ]; then
|
|
cp /var/www/atom-nexst/.env "$SRC/.env"
|
|
fi
|
|
cd "$SRC"
|
|
pnpm install --frozen-lockfile
|
|
pnpm prisma:generate
|
|
export SKIP_ENV_VALIDATION=1
|
|
pnpm build
|
|
|
|
# Create release — Python reads changelog directly from git
|
|
python3 << 'PYEOF'
|
|
import json, os, subprocess, urllib.request, urllib.error
|
|
|
|
version = os.environ["VERSION"]
|
|
api = os.environ["GITEA_API"]
|
|
repo = os.environ["GITEA_REPO"]
|
|
token = "${{ secrets.GITEA_TOKEN }}"
|
|
local = "/var/www/atom-nexst"
|
|
|
|
# Get previous tag
|
|
tags = subprocess.run(
|
|
["git", "-C", local, "tag", "--sort=-creatordate"],
|
|
capture_output=True, text=True, check=False,
|
|
).stdout.strip().split("\n")
|
|
tags = [t for t in tags if t]
|
|
|
|
prev_tag = tags[1] if len(tags) > 1 else ""
|
|
print(f"Tags: {tags}")
|
|
print(f"Version: {version}, Previous: {prev_tag}")
|
|
|
|
if prev_tag and prev_tag != version:
|
|
r = subprocess.run(
|
|
["git", "-C", local, "log", "--oneline", "--no-decorate", f"{prev_tag}..{version}"],
|
|
capture_output=True, text=True, check=False,
|
|
)
|
|
notes_raw = r.stdout.strip()
|
|
print(f"Range: {prev_tag}..{version}, stderr: {r.stderr.strip()}")
|
|
else:
|
|
r = subprocess.run(
|
|
["git", "-C", local, "log", "--oneline", "--no-decorate", version],
|
|
capture_output=True, text=True, check=False,
|
|
)
|
|
notes_raw = r.stdout.strip()
|
|
print(f"Single tag {version}, stderr: {r.stderr.strip()}")
|
|
|
|
if not notes_raw:
|
|
notes_raw = "Initial release"
|
|
|
|
print(f"Notes ({len(notes_raw)} chars):")
|
|
print(notes_raw)
|
|
print("=== End notes ===")
|
|
|
|
body = f"""## EpicNext-CMS {version}
|
|
|
|
### Changes
|
|
{notes_raw}
|
|
|
|
---
|
|
*Automated release from Gitea Actions*
|
|
"""
|
|
|
|
payload = json.dumps({
|
|
"tag_name": version,
|
|
"name": version,
|
|
"body": body,
|
|
"draft": False,
|
|
"prerelease": False,
|
|
}).encode("utf-8")
|
|
|
|
def api_call(method, path, data=None):
|
|
url = f"{api}/repos/{repo}/{path}"
|
|
print(f"API {method} {url}")
|
|
req = urllib.request.Request(
|
|
url, data=data,
|
|
headers={
|
|
"Authorization": f"token {token}",
|
|
"Content-Type": "application/json",
|
|
},
|
|
method=method,
|
|
)
|
|
resp = urllib.request.urlopen(req)
|
|
return json.loads(resp.read().decode("utf-8"))
|
|
|
|
try:
|
|
result = api_call("POST", "releases", payload)
|
|
print(f"Release created: {result.get('html_url', result.get('id', '?'))}")
|
|
except urllib.error.HTTPError as e:
|
|
err_body = e.read().decode("utf-8")
|
|
print(f"POST error {e.code}: {err_body}")
|
|
if e.code == 409:
|
|
releases = api_call("GET", "releases")
|
|
for rel in releases:
|
|
if rel["tag_name"] == version:
|
|
result = api_call("PATCH", f"releases/{rel['id']}", payload)
|
|
print(f"Release updated: {result.get('html_url', result.get('id', '?'))}")
|
|
break
|
|
else:
|
|
print(f"ERROR: no existing release found for {version}")
|
|
raise
|
|
else:
|
|
raise
|
|
PYEOF
|