Local Build and Deploy / deploy (push) Successful in 1m26s
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
|