Skip to content

Release

Release #25

Workflow file for this run

name: Release
on:
workflow_run:
workflows: ["CI"]
types:
- completed
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
IMAGE_DESCRIPTION: >
CinePro Core is the central scraping and streaming engine of the CinePro
ecosystem. It exposes an OMSS-compliant HTTP API for resolving movie and TV
show streams from multiple providers.
concurrency:
group: docker-build-${{ github.event.workflow_run.head_branch || github.ref }}
cancel-in-progress: true
jobs:
prepare:
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_branch == 'main')
runs-on: ubuntu-latest
outputs:
app_version: ${{ steps.meta.outputs.app_version }}
arch_tag_amd64: ${{ steps.meta.outputs.arch_tag_amd64 }}
arch_tag_arm64: ${{ steps.meta.outputs.arch_tag_arm64 }}
created: ${{ steps.meta.outputs.created }}
steps:
- id: meta
run: |
SHA="${{ github.event.workflow_run.head_sha || github.sha }}"
SHORT_SHA="${SHA::7}"
APP_VERSION="main-${SHORT_SHA}"
CREATED="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
{
echo "app_version=${APP_VERSION}"
echo "arch_tag_amd64=${APP_VERSION}-amd64"
echo "arch_tag_arm64=${APP_VERSION}-arm64"
echo "created=${CREATED}"
} >> "$GITHUB_OUTPUT"
build-amd64:
runs-on: ubuntu-latest
needs: [prepare]
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build-push.outputs.digest }}
steps:
- uses: actions/checkout@v4
- name: Set lowercase image name
run: echo "IMAGE_NAME_LC=${GITHUB_REPOSITORY,,}" >> "$GITHUB_ENV"
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
if: github.event_name != 'pull_request'
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build test image
run: docker buildx build --load -t cinepro-core:test .
- name: Test Docker image
run: |
docker run -d --name cinepro-core-test \
-p 3000:3000 \
-e NODE_ENV=production \
-e HOST=0.0.0.0 \
-e PORT=3000 \
-e CACHE_TYPE=memory \
-e TMDB_API_KEY=dummy-ci-key \
cinepro-core:test
sleep 10
docker logs cinepro-core-test
curl -sf http://localhost:3000 || true
- name: Cleanup test container
if: always()
run: docker rm -f cinepro-core-test || true
- name: Build and push Docker image (amd64)
id: build-push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64
push: ${{ github.event_name != 'pull_request' }}
provenance: false
sbom: false
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_LC }}:${{ needs.prepare.outputs.arch_tag_amd64 }}
cache-from: type=gha,scope=amd64
cache-to: type=gha,mode=max,scope=amd64
build-args: |
VERSION=${{ needs.prepare.outputs.app_version }}
REVISION=${{ github.event.workflow_run.head_sha }}
CREATED=${{ needs.prepare.outputs.created }}
DESCRIPTION=${{ env.IMAGE_DESCRIPTION }}
SOURCE=${{ github.server_url }}/${{ github.repository }}
build-arm64:
runs-on: ubuntu-24.04-arm
needs: [prepare]
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build-push.outputs.digest }}
steps:
- uses: actions/checkout@v4
- name: Set lowercase image name
run: echo "IMAGE_NAME_LC=${GITHUB_REPOSITORY,,}" >> "$GITHUB_ENV"
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
if: github.event_name != 'pull_request'
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image (arm64)
id: build-push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/arm64
push: ${{ github.event_name != 'pull_request' }}
provenance: false
sbom: false
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_LC }}:${{ needs.prepare.outputs.arch_tag_arm64 }}
cache-from: type=gha,scope=arm64
cache-to: type=gha,mode=max,scope=arm64
build-args: |
VERSION=${{ needs.prepare.outputs.app_version }}
REVISION=${{ github.event.workflow_run.head_sha }}
CREATED=${{ needs.prepare.outputs.created }}
DESCRIPTION=${{ env.IMAGE_DESCRIPTION }}
SOURCE=${{ github.server_url }}/${{ github.repository }}
manifest:
runs-on: ubuntu-latest
needs: [prepare, build-amd64, build-arm64]
if: >-
github.event_name != 'pull_request' &&
needs.prepare.result == 'success' &&
needs.build-amd64.result == 'success' &&
needs.build-arm64.result == 'success'
permissions:
contents: write
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set lowercase image name
run: echo "IMAGE_NAME_LC=${GITHUB_REPOSITORY,,}" >> "$GITHUB_ENV"
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/setup-buildx-action@v3
- name: Create and push multi-arch manifests with description
run: |
IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME_LC }}"
AMD64_IMAGE="$IMAGE:${{ needs.prepare.outputs.arch_tag_amd64 }}"
ARM64_IMAGE="$IMAGE:${{ needs.prepare.outputs.arch_tag_arm64 }}"
DESC="${{ env.IMAGE_DESCRIPTION }}"
# Versioned tag
docker buildx imagetools create \
--annotation "index:org.opencontainers.image.description=${DESC}" \
-t "$IMAGE:${{ needs.prepare.outputs.app_version }}" \
"$AMD64_IMAGE" "$ARM64_IMAGE"
# Moving tags
docker buildx imagetools create \
--annotation "index:org.opencontainers.image.description=${DESC}" \
-t "$IMAGE:main" \
"$AMD64_IMAGE" "$ARM64_IMAGE"
docker buildx imagetools create \
--annotation "index:org.opencontainers.image.description=${DESC}" \
-t "$IMAGE:latest" \
"$AMD64_IMAGE" "$ARM64_IMAGE"
- name: Generate categorized release notes
id: release_notes
run: |
CURRENT_TAG="${{ needs.prepare.outputs.app_version }}"
PREV_TAG="${{ needs.prepare.outputs.previous_tag }}"
if [ -n "$PREV_TAG" ]; then
HASHES=$(git log --pretty=format:"%H" "$PREV_TAG"..origin/main)
echo "Commits since $PREV_TAG:"
else
HASHES=$(git log --pretty=format:"%H" origin/main -n 50)
echo "No previous tag found, using last 50 commits on main"
fi
FEATURES=""
FIXES=""
DOCS=""
CHORES=""
BREAKING=""
OTHERS=""
while IFS= read -r hash; do
# Get first line only, escape for bash/YAML safely
message=$(git log --format=%s -n 1 "$hash" | head -n1 | sed 's/"/\\"/g; s/`/\\`/g; s/$/\n/g')
short_hash=$(git log --format=%h -n 1 "$hash")
echo "Processing: '$message' ($short_hash)"
# Safe prefix extraction
if echo "$message" | grep -q '^[^:]*:'; then
clean_message=$(echo "$message" | sed 's/^[^:]*: *//')
else
clean_message="$message"
fi
REPO_URL="${{ github.server_url }}/${{ github.repository }}"
LINK="[${clean_message}](${REPO_URL}/commit/${short_hash})"
case "$message" in
feat:*|feat\(*|feature:*)
FEATURES="${FEATURES}- feat: ${LINK}"
;;
fix:*|fix\(*)
FIXES="${FIXES}- fix: ${LINK}"
;;
docs:*|docs\(*)
DOCS="${DOCS}- docs: ${LINK}"
;;
chore:*|chore\(*|ci:*|ci\(*|build:*|build\(*)
CHORES="${CHORES}- chore: ${LINK}"
;;
*BREAKING*|*breaking*|*!:*)
BREAKING="${BREAKING}- breaking change: [${message}](${REPO_URL}/commit/${short_hash})"
;;
*)
OTHERS="${OTHERS}- ${LINK}"
;;
esac
done <<< "$HASHES"
NOTES="## Release $CURRENT_TAG"
if [ -n "$PREV_TAG" ]; then
NOTES="${NOTES}Changes since \`${PREV_TAG}\`:"
fi
NOTES="${NOTES}Release commit: [\`${{ github.event.workflow_run.head_sha || github.sha }}\`](${REPO_URL}/commit/${{ github.event.workflow_run.head_sha || github.sha }})."
[ -n "$BREAKING" ] && NOTES="${NOTES}### ⚠️ Breaking Changes$(printf %s "$BREAKING")"
[ -n "$FEATURES" ] && NOTES="${NOTES}### ✨ Features$(printf %s "$FEATURES")"
[ -n "$FIXES" ] && NOTES="${NOTES}### 🐛 Bug Fixes$(printf %s "$FIXES")"
[ -n "$DOCS" ] && NOTES="${NOTES}### 📚 Documentation$(printf %s "$DOCS")"
[ -n "$CHORES" ] && NOTES="${NOTES}### 🔧 Maintenance$(printf %s "$CHORES")"
[ -n "$OTHERS" ] && NOTES="${NOTES}### 📦 Other Changes$(printf %s "$OTHERS")"
NOTES="${NOTES}## Quick startStart the latest version:\`\`\`bashdocker run --name cinepro-core-${{ needs.prepare.outputs.app_version }} -p 3000:3000 -e TMDB_API_KEY=your-tmdb-key ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_LC }}:latest\`\`\`## For more details, check the [CinePro documentation](https://docs.cinepro.cc) and the [Version History](https://docs.cinepro.cc/core/versions)."
{
echo "notes<<EOF"
printf '%s\n' "$NOTES"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Create GitHub Release
uses: softprops/action-gh-release@v2.5.0
with:
name: Release ${{ needs.prepare.outputs.app_version }}
body: ${{ steps.release_notes.outputs.notes }}
draft: false
generate_release_notes: false
tag_name: ${{ needs.prepare.outputs.app_version }}
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}