Add reusable Forgejo Actions

Composite actions for CI/CD workflows:
- checkout: Clone repo with configurable depth
- docker-build: Build Docker images with multiple tags
- docker-push: Push to Forgejo Packages registry
- create-tag: Auto-increment semantic version tags
- create-issue: Create issues via Forgejo API
- create-pr: Create pull requests via Forgejo API
- comment-pr: Add comments to PRs via Forgejo API

All actions use shell scripts (no Node.js required).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-25 23:16:20 +01:00
commit 14d7cae864
7 changed files with 379 additions and 0 deletions

28
checkout/action.yaml Normal file
View File

@@ -0,0 +1,28 @@
name: Checkout
description: Clone repository with configurable depth
inputs:
repository:
description: Repository to clone (owner/repo)
default: ${{ github.repository }}
ref:
description: Branch, tag, or SHA to checkout
default: ${{ github.ref_name }}
depth:
description: Clone depth (0 for full history)
default: '1'
token:
description: Token for private repositories
default: ${{ github.token }}
runs:
using: composite
steps:
- shell: bash
run: |
if [ "${{ inputs.depth }}" = "0" ]; then
git clone "https://oauth2:${{ inputs.token }}@code.flowmade.one/${{ inputs.repository }}.git" .
else
git clone --depth "${{ inputs.depth }}" --branch "${{ inputs.ref }}" \
"https://oauth2:${{ inputs.token }}@code.flowmade.one/${{ inputs.repository }}.git" .
fi

43
comment-pr/action.yaml Normal file
View File

@@ -0,0 +1,43 @@
name: Comment on PR
description: Add a comment to a pull request via Forgejo API
inputs:
token:
description: Forgejo API token
required: true
repository:
description: Repository (owner/repo)
default: ${{ github.repository }}
pr-number:
description: Pull request number
required: true
body:
description: Comment body
required: true
outputs:
id:
description: Created comment ID
value: ${{ steps.comment.outputs.id }}
runs:
using: composite
steps:
- id: comment
shell: bash
run: |
TOKEN="${{ inputs.token }}"
REPO="${{ inputs.repository }}"
PR_NUMBER="${{ inputs.pr-number }}"
BODY="${{ inputs.body }}"
JSON=$(jq -n --arg body "$BODY" '{body: $body}')
RESPONSE=$(curl -s -X POST \
"https://code.flowmade.one/api/v1/repos/$REPO/issues/$PR_NUMBER/comments" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "$JSON")
ID=$(echo "$RESPONSE" | jq -r '.id')
echo "id=$ID" >> $GITHUB_OUTPUT

73
create-issue/action.yaml Normal file
View File

@@ -0,0 +1,73 @@
name: Create Issue
description: Create an issue via Forgejo API
inputs:
token:
description: Forgejo API token
required: true
repository:
description: Repository (owner/repo)
default: ${{ github.repository }}
title:
description: Issue title
required: true
body:
description: Issue body
default: ''
labels:
description: Comma-separated label names
default: ''
assignees:
description: Comma-separated usernames to assign
default: ''
outputs:
number:
description: Created issue number
value: ${{ steps.create.outputs.number }}
url:
description: Issue URL
value: ${{ steps.create.outputs.url }}
runs:
using: composite
steps:
- id: create
shell: bash
run: |
TOKEN="${{ inputs.token }}"
REPO="${{ inputs.repository }}"
TITLE="${{ inputs.title }}"
BODY="${{ inputs.body }}"
LABELS="${{ inputs.labels }}"
ASSIGNEES="${{ inputs.assignees }}"
# Build JSON payload
JSON=$(jq -n \
--arg title "$TITLE" \
--arg body "$BODY" \
'{title: $title, body: $body}')
# Add labels if provided
if [ -n "$LABELS" ]; then
LABELS_JSON=$(echo "$LABELS" | tr ',' '\n' | jq -R . | jq -s .)
JSON=$(echo "$JSON" | jq --argjson labels "$LABELS_JSON" '. + {labels: $labels}')
fi
# Add assignees if provided
if [ -n "$ASSIGNEES" ]; then
ASSIGNEES_JSON=$(echo "$ASSIGNEES" | tr ',' '\n' | jq -R . | jq -s .)
JSON=$(echo "$JSON" | jq --argjson assignees "$ASSIGNEES_JSON" '. + {assignees: $assignees}')
fi
RESPONSE=$(curl -s -X POST \
"https://code.flowmade.one/api/v1/repos/$REPO/issues" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "$JSON")
NUMBER=$(echo "$RESPONSE" | jq -r '.number')
URL=$(echo "$RESPONSE" | jq -r '.html_url')
echo "number=$NUMBER" >> $GITHUB_OUTPUT
echo "url=$URL" >> $GITHUB_OUTPUT

83
create-pr/action.yaml Normal file
View File

@@ -0,0 +1,83 @@
name: Create Pull Request
description: Create a pull request via Forgejo API
inputs:
token:
description: Forgejo API token
required: true
repository:
description: Repository (owner/repo)
default: ${{ github.repository }}
title:
description: Pull request title
required: true
body:
description: Pull request body
default: ''
head:
description: Source branch
required: true
base:
description: Target branch
default: 'main'
labels:
description: Comma-separated label names
default: ''
assignees:
description: Comma-separated usernames to assign
default: ''
outputs:
number:
description: Created PR number
value: ${{ steps.create.outputs.number }}
url:
description: PR URL
value: ${{ steps.create.outputs.url }}
runs:
using: composite
steps:
- id: create
shell: bash
run: |
TOKEN="${{ inputs.token }}"
REPO="${{ inputs.repository }}"
TITLE="${{ inputs.title }}"
BODY="${{ inputs.body }}"
HEAD="${{ inputs.head }}"
BASE="${{ inputs.base }}"
LABELS="${{ inputs.labels }}"
ASSIGNEES="${{ inputs.assignees }}"
# Build JSON payload
JSON=$(jq -n \
--arg title "$TITLE" \
--arg body "$BODY" \
--arg head "$HEAD" \
--arg base "$BASE" \
'{title: $title, body: $body, head: $head, base: $base}')
# Add labels if provided
if [ -n "$LABELS" ]; then
LABELS_JSON=$(echo "$LABELS" | tr ',' '\n' | jq -R . | jq -s .)
JSON=$(echo "$JSON" | jq --argjson labels "$LABELS_JSON" '. + {labels: $labels}')
fi
# Add assignees if provided
if [ -n "$ASSIGNEES" ]; then
ASSIGNEES_JSON=$(echo "$ASSIGNEES" | tr ',' '\n' | jq -R . | jq -s .)
JSON=$(echo "$JSON" | jq --argjson assignees "$ASSIGNEES_JSON" '. + {assignees: $assignees}')
fi
RESPONSE=$(curl -s -X POST \
"https://code.flowmade.one/api/v1/repos/$REPO/pulls" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "$JSON")
NUMBER=$(echo "$RESPONSE" | jq -r '.number')
URL=$(echo "$RESPONSE" | jq -r '.html_url')
echo "number=$NUMBER" >> $GITHUB_OUTPUT
echo "url=$URL" >> $GITHUB_OUTPUT

49
create-tag/action.yaml Normal file
View File

@@ -0,0 +1,49 @@
name: Create Tag
description: Auto-increment and create a version tag
inputs:
prefix:
description: Tag prefix (e.g., 'v', 'myapp-v')
default: 'v'
token:
description: Token for pushing tags
default: ${{ github.token }}
outputs:
tag:
description: The created tag name
value: ${{ steps.version.outputs.tag }}
version:
description: The version number without prefix
value: ${{ steps.version.outputs.version }}
runs:
using: composite
steps:
- id: version
shell: bash
run: |
PREFIX="${{ inputs.prefix }}"
# Find latest tag with this prefix
LATEST_TAG=$(git tag -l "${PREFIX}*" | sort -V | tail -1)
if [ -z "$LATEST_TAG" ]; then
NEXT_VERSION="${PREFIX}1.0.0"
else
# Extract version and increment patch
CURRENT_VERSION=${LATEST_TAG#$PREFIX}
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
NEXT_VERSION="${PREFIX}${MAJOR}.${MINOR}.$((PATCH + 1))"
fi
echo "tag=$NEXT_VERSION" >> $GITHUB_OUTPUT
echo "version=${NEXT_VERSION#$PREFIX}" >> $GITHUB_OUTPUT
# Configure git and create tag
git config user.name forgejo-actions
git config user.email forgejo-actions@code.flowmade.one
git tag "$NEXT_VERSION"
# Push tag using token
git push "https://oauth2:${{ inputs.token }}@code.flowmade.one/${{ github.repository }}.git" "$NEXT_VERSION"

62
docker-build/action.yaml Normal file
View File

@@ -0,0 +1,62 @@
name: Docker Build
description: Build a Docker image with tags
inputs:
image:
description: Full image name (registry/org/name)
required: true
tags:
description: Comma-separated list of tags
default: 'latest'
context:
description: Build context path
default: '.'
dockerfile:
description: Path to Dockerfile
default: 'Dockerfile'
build-args:
description: Build arguments (KEY=value, newline-separated)
default: ''
outputs:
images:
description: Built image references
value: ${{ steps.build.outputs.images }}
runs:
using: composite
steps:
- id: build
shell: bash
run: |
IMAGE="${{ inputs.image }}"
TAGS="${{ inputs.tags }}"
CONTEXT="${{ inputs.context }}"
DOCKERFILE="${{ inputs.dockerfile }}"
BUILD_ARGS="${{ inputs.build-args }}"
# Build tag arguments
TAG_ARGS=""
IMAGES=""
IFS=',' read -ra TAG_ARRAY <<< "$TAGS"
for tag in "${TAG_ARRAY[@]}"; do
tag=$(echo "$tag" | xargs) # trim whitespace
TAG_ARGS="$TAG_ARGS -t $IMAGE:$tag"
IMAGES="$IMAGES$IMAGE:$tag,"
done
IMAGES="${IMAGES%,}" # remove trailing comma
# Build build-arg arguments
BUILD_ARG_ARGS=""
if [ -n "$BUILD_ARGS" ]; then
while IFS= read -r arg; do
if [ -n "$arg" ]; then
BUILD_ARG_ARGS="$BUILD_ARG_ARGS --build-arg $arg"
fi
done <<< "$BUILD_ARGS"
fi
# Build the image
docker build $TAG_ARGS $BUILD_ARG_ARGS -f "$DOCKERFILE" "$CONTEXT"
echo "images=$IMAGES" >> $GITHUB_OUTPUT

41
docker-push/action.yaml Normal file
View File

@@ -0,0 +1,41 @@
name: Docker Push
description: Push Docker image to Forgejo Packages registry
inputs:
image:
description: Full image name (registry/org/name)
required: true
tags:
description: Comma-separated list of tags to push
default: 'latest'
registry:
description: Registry URL
default: 'code.flowmade.one'
username:
description: Registry username
default: ${{ github.repository_owner }}
password:
description: Registry password/token
required: true
runs:
using: composite
steps:
- shell: bash
run: |
IMAGE="${{ inputs.image }}"
TAGS="${{ inputs.tags }}"
REGISTRY="${{ inputs.registry }}"
USERNAME="${{ inputs.username }}"
PASSWORD="${{ inputs.password }}"
# Login to registry
echo "$PASSWORD" | docker login "$REGISTRY" -u "$USERNAME" --password-stdin
# Push each tag
IFS=',' read -ra TAG_ARRAY <<< "$TAGS"
for tag in "${TAG_ARRAY[@]}"; do
tag=$(echo "$tag" | xargs) # trim whitespace
echo "Pushing $IMAGE:$tag"
docker push "$IMAGE:$tag"
done