name: Create Blog Post on: workflow_dispatch: inputs: title: description: "Post title" required: true type: string slug: description: "URL slug, for example my-new-post" required: true type: string summary: description: "Short summary" required: false type: string tags: description: "Comma-separated tags" required: false type: string categories: description: "Comma-separated categories" required: false type: string draft: description: "Create as draft" required: true type: boolean default: true jobs: create-post: runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout source uses: actions/checkout@v4 with: fetch-depth: 0 - name: Generate post file env: INPUT_TITLE: ${{ inputs.title }} INPUT_SLUG: ${{ inputs.slug }} INPUT_SUMMARY: ${{ inputs.summary }} INPUT_TAGS: ${{ inputs.tags }} INPUT_CATEGORIES: ${{ inputs.categories }} INPUT_DRAFT: ${{ inputs.draft }} run: | python3 - <<'PY' import os import re from datetime import datetime, timezone from pathlib import Path def split_csv(value: str): if not value: return [] return [item.strip() for item in value.split(",") if item.strip()] title = os.environ["INPUT_TITLE"].strip() slug = os.environ["INPUT_SLUG"].strip().lower() summary = os.environ.get("INPUT_SUMMARY", "").strip() draft = os.environ.get("INPUT_DRAFT", "true").strip().lower() == "true" tags = split_csv(os.environ.get("INPUT_TAGS", "")) categories = split_csv(os.environ.get("INPUT_CATEGORIES", "")) if not title: raise SystemExit("Title is required") if not re.fullmatch(r"[a-z0-9]+(?:-[a-z0-9]+)*", slug): raise SystemExit("Slug must use lowercase letters, numbers, and hyphens only") content_dir = Path("content/posts") content_dir.mkdir(parents=True, exist_ok=True) target = content_dir / f"{slug}.md" if target.exists(): raise SystemExit(f"Post already exists: {target}") now = datetime.now(timezone.utc).astimezone().replace(microsecond=0).isoformat() def format_array(values): if not values: return "[]" return "[{}]".format(", ".join(f'\"{value}\"' for value in values)) escaped_title = title.replace('"', '\\"') escaped_summary = summary.replace('"', '\\"') body = f"""++++ title = \"{escaped_title}\" date = {now} draft = {\"true\" if draft else \"false\"} slug = \"{slug}\" summary = \"{escaped_summary}\" tags = {format_array(tags)} categories = {format_array(categories)} ++++ Write your post here. """ target.write_text(body, encoding="utf-8") print(target) PY - name: Commit new post env: POST_SLUG: ${{ inputs.slug }} run: | git config user.name "forgejo-actions" git config user.email "forgejo-actions@localhost" git add "content/posts/${POST_SLUG}.md" git commit -m "Create post: ${POST_SLUG}" git push