fix: generate changelog via Python subprocess for reliability
Local Build and Deploy / deploy (push) Successful in 1m26s
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.
This commit is contained in:
1 parent
80bf3bb0d5
commit
57ef6289ff
1 file changed
+75
-51
@@ -7,7 +7,7 @@ jobs:
|
||||
release:
|
||||
runs-on: shell
|
||||
steps:
|
||||
- name: Checkout, build & release
|
||||
- name: Build & release
|
||||
env:
|
||||
VERSION: ${{ gitea.ref_name }}
|
||||
GITEA_API: ${{ gitea.api_url }}
|
||||
@@ -15,90 +15,114 @@ jobs:
|
||||
run: |
|
||||
set -e
|
||||
|
||||
# Use the local checkout (has full history + HEAD)
|
||||
LOCAL="/var/www/atom-nexst"
|
||||
|
||||
# ── Generate changelog ────────────────────────────────────────
|
||||
PREV_TAG="$(git -C "$LOCAL" tag --sort=-creatordate | head -2 | tail -1 || echo '')"
|
||||
echo "=== Debug: VERSION=$VERSION PREV_TAG=$PREV_TAG ==="
|
||||
|
||||
if [ -n "$PREV_TAG" ] && [ "$PREV_TAG" != "$VERSION" ]; then
|
||||
RANGE="${PREV_TAG}..${VERSION}"
|
||||
echo "=== Range: $RANGE ==="
|
||||
git -C "$LOCAL" log --oneline --no-decorate "${RANGE}" > /tmp/changelog.txt
|
||||
else
|
||||
# First release or only one tag — show all commits up to this tag
|
||||
echo "=== First release or only one tag, showing all commits ==="
|
||||
git -C "$LOCAL" log --oneline --no-decorate "${VERSION}" > /tmp/changelog.txt
|
||||
fi
|
||||
|
||||
echo "=== Changelog ==="
|
||||
cat /tmp/changelog.txt
|
||||
echo "=== End changelog ==="
|
||||
|
||||
# ── Build ─────────────────────────────────────────────────────
|
||||
# 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"
|
||||
cd "$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 handles JSON properly) ─────────────
|
||||
# Create release — Python reads changelog directly from git
|
||||
python3 << 'PYEOF'
|
||||
import json, os, urllib.request
|
||||
import json, os, subprocess, urllib.request, urllib.error
|
||||
|
||||
version = os.environ['VERSION']
|
||||
api = os.environ['GITEA_API']
|
||||
repo = os.environ['GITEA_REPO']
|
||||
version = os.environ["VERSION"]
|
||||
api = os.environ["GITEA_API"]
|
||||
repo = os.environ["GITEA_REPO"]
|
||||
token = "${{ secrets.GITEA_TOKEN }}"
|
||||
local = "/var/www/atom-nexst"
|
||||
|
||||
with open('/tmp/changelog.txt') as f:
|
||||
notes = f.read().strip()
|
||||
# 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]
|
||||
|
||||
if not notes:
|
||||
notes = "Initial release"
|
||||
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}
|
||||
{notes_raw}
|
||||
|
||||
---
|
||||
*Automated release from Gitea Actions*
|
||||
"""
|
||||
|
||||
payload = json.dumps({
|
||||
'tag_name': version,
|
||||
'name': version,
|
||||
'body': body,
|
||||
'draft': False,
|
||||
'prerelease': False,
|
||||
}).encode('utf-8')
|
||||
"tag_name": version,
|
||||
"name": version,
|
||||
"body": body,
|
||||
"draft": False,
|
||||
"prerelease": False,
|
||||
}).encode("utf-8")
|
||||
|
||||
req = urllib.request.Request(
|
||||
f'{api}/repos/{repo}/releases',
|
||||
data=payload,
|
||||
headers={
|
||||
'Authorization': f'token {token}',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method='POST',
|
||||
)
|
||||
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:
|
||||
resp = urllib.request.urlopen(req)
|
||||
result = json.loads(resp.read().decode('utf-8'))
|
||||
result = api_call("POST", "releases", payload)
|
||||
print(f"Release created: {result.get('html_url', result.get('id', '?'))}")
|
||||
except urllib.error.HTTPError as e:
|
||||
print(f"API error {e.code}: {e.read().decode('utf-8')}")
|
||||
raise
|
||||
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
|
||||
Reference in new issue
Block a user