name: Release and Build Image on: push: tags: - "v*" jobs: release: runs-on: ubuntu-latest steps: - name: Check out repository uses: actions/checkout@v4 - name: Prepare release metadata shell: bash run: | TAG="${GITHUB_REF_NAME:-${GITHUB_REF##refs/tags/}}" VERSION="${TAG#v}" IMAGE_REGISTRY="${{ gitea.server_url }}" IMAGE_REGISTRY="${IMAGE_REGISTRY#http://}" IMAGE_REGISTRY="${IMAGE_REGISTRY#https://}" IMAGE_NAME="${IMAGE_REGISTRY}/${{ gitea.repository }}" echo "TAG=$TAG" >> "$GITHUB_ENV" echo "VERSION=$VERSION" >> "$GITHUB_ENV" echo "IMAGE_NAME=$IMAGE_NAME" >> "$GITHUB_ENV" if [[ "$TAG" == *-* ]]; then echo "PRERELEASE=true" >> "$GITHUB_ENV" else echo "PRERELEASE=false" >> "$GITHUB_ENV" fi - name: Extract matching CHANGELOG section shell: bash run: | python3 - <<'PY' import os import re from pathlib import Path version = os.environ["VERSION"] changelog_path = Path("CHANGELOG.md") if not changelog_path.exists(): body = f"# {version}\n\nNo CHANGELOG.md found." Path("release_body.md").write_text(body, encoding="utf-8") raise SystemExit(0) text = changelog_path.read_text(encoding="utf-8") pattern = re.compile( rf"^##\s+\[?{re.escape(version)}\]?[^\n]*\n(.*?)(?=^##\s+\[?[0-9]|\Z)", re.MULTILINE | re.DOTALL, ) match = pattern.search(text) if match: body = match.group(1).strip() else: body = f"Release {version}" if not body: body = f"Release {version}" Path("release_body.md").write_text(body + "\n", encoding="utf-8") PY - name: Log in to Gitea container registry shell: bash env: REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }} REGISTRY_TOKEN: ${{ secrets.RELEASE_TOKEN }} run: | echo "$REGISTRY_TOKEN" | docker login "${IMAGE_NAME%%/*}" -u "$REGISTRY_USERNAME" --password-stdin - name: Build Docker image shell: bash run: | docker build \ -t "$IMAGE_NAME:$TAG" \ -t "$IMAGE_NAME:latest" \ . - name: Push version tag shell: bash run: | docker push "$IMAGE_NAME:$TAG" - name: Push latest tag if: ${{ !contains(env.TAG, '-') }} shell: bash run: | docker push "$IMAGE_NAME:latest" - name: Push prerelease channel tag if: ${{ contains(env.TAG, '-') }} shell: bash run: | CHANNEL="${TAG#*-}" CHANNEL="${CHANNEL%%.*}" docker tag "$IMAGE_NAME:$TAG" "$IMAGE_NAME:$CHANNEL" docker push "$IMAGE_NAME:$CHANNEL" - name: Create Gitea release env: RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} GITEA_SERVER_URL: ${{ gitea.server_url }} GITEA_REPOSITORY: ${{ gitea.repository }} shell: bash run: | python3 - <<'PY' import json import os import urllib.request import urllib.error tag = os.environ["TAG"] prerelease = os.environ["PRERELEASE"].lower() == "true" server_url = os.environ["GITEA_SERVER_URL"].rstrip("/") repo = os.environ["GITEA_REPOSITORY"] token = os.environ["RELEASE_TOKEN"] image_name = os.environ["IMAGE_NAME"] tag = os.environ["TAG"] with open("release_body.md", "r", encoding="utf-8") as f: changelog_body = f.read() header = ( "## 🚀 How to run this release\n\n" "### Pull image\n" f"```bash\n" f"docker pull {image_name}:{tag}\n" f"```\n\n" "### Run container\n" f"```bash\n" f"docker run -d \\\n" f" --name lst \\\n" f" -p 3000:3000 \\\n" f" {image_name}:{tag}\n" f"```\n\n" "---\n\n" ) import os import re from pathlib import Path version = os.environ["VERSION"] changelog_path = Path("CHANGELOG.md") if not changelog_path.exists(): Path("release_body.md").write_text(f"Release {version}\n", encoding="utf-8") raise SystemExit(0) text = changelog_path.read_text(encoding="utf-8") pattern = re.compile( rf"^##\s+{re.escape(version)}(?:\s*\([^)]+\))?\n(.*?)(?=^##\s+[0-9]|\Z)", re.MULTILINE | re.DOTALL, ) match = pattern.search(text) if match: body = match.group(1).strip() else: body = f"Release {version}" Path("release_body.md").write_text(body + "\n", encoding="utf-8") url = f"{server_url}/api/v1/repos/{repo}/releases" payload = { "tag_name": tag, "name": tag, "body": body, "draft": False, "prerelease": prerelease, } data = json.dumps(payload).encode("utf-8") req = urllib.request.Request( url, data=data, method="POST", headers={ "Authorization": f"token {token}", "Content-Type": "application/json", "Accept": "application/json", }, ) try: with urllib.request.urlopen(req) as resp: print(resp.read().decode("utf-8")) except urllib.error.HTTPError as e: details = e.read().decode("utf-8", errors="replace") print(details) raise PY