Skip to content

Publish Article

Publish Article #4

name: Publish Article
on:
workflow_dispatch:
inputs:
file_name:
description: 'The filename OR folder name of the draft in _posts/prepub/ (e.g., my-awesome-d-article.md or my-awesome-d-article/)'
required: true
pub_date:
description: "Optional: Custom date (YYYY-MM-DD). Leave blank for today's date."
required: false
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Validate Draft
run: |
FULL_PATH="_posts/prepub/${{ github.event.inputs.file_name }}"
# 1. Existence check
if [[ ! -e "$FULL_PATH" ]]; then
echo "Error: Target '$FULL_PATH' not found in the prepub folder."
exit 1
fi
# Locate the markdown file whether it's standalone or inside a folder
if [[ -d "$FULL_PATH" ]]; then
MD_FILE=$(find "$FULL_PATH" -maxdepth 1 -name "*.md" | head -n 1)
if [[ -z "$MD_FILE" ]]; then
echo "Error: No markdown file found inside directory '$FULL_PATH'."
exit 1
fi
CHECK_FILE="$MD_FILE"
else
CHECK_FILE="$FULL_PATH"
fi
# 2. Date format check (if provided)
CUSTOM_DATE="${{ github.event.inputs.pub_date }}"
if [[ -n "$CUSTOM_DATE" && ! "$CUSTOM_DATE" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
echo "Error: Custom date must be in YYYY-MM-DD format."
exit 1
fi
# 3. Front Matter gatekeeping
# Strip Windows BOM and CR line ending, just in case
if [[ ! $(head -n 1 "$CHECK_FILE" | tr -d '\r' | sed '1s/^\xEF\xBB\xBF//') == "---" ]]; then
echo "Error: Missing starting Front Matter delimiter (---) in $CHECK_FILE"
exit 1
fi
- name: Process and Route Content
id: process
run: |
INPUT_NAME="${{ github.event.inputs.file_name }}"
FULL_PATH="_posts/prepub/$INPUT_NAME"
INPUT_DATE="${{ github.event.inputs.pub_date }}"
DATE=${INPUT_DATE:-$(date +'%Y-%m-%d')}
# Strip any existing YYYY-MM-DD prefix from the filename to prevent double-dating
CLEAN_SLUG=$(echo "$INPUT_NAME" | sed -E 's/^[0-9]{4}-[0-9]{2}-[0-9]{2}-//' | sed 's/\.md$//')
CLEAN_FILENAME="${DATE}-${CLEAN_SLUG}.md"
mkdir -p _posts/live
if [[ -d "$FULL_PATH" ]]; then
# --- FOLDER ROUTING LOGIC ---
MD_FILE=$(find "$FULL_PATH" -maxdepth 1 -name "*.md" | head -n 1)
# Create the dedicated assets directory for this post
mkdir -p "assets/images/$CLEAN_SLUG"
# Move all non-markdown files (images, gifs, etc.) to the assets folder
find "$FULL_PATH" -maxdepth 1 -type f ! -name "*.md" -exec mv {} "assets/images/$CLEAN_SLUG/" \;
# Move the markdown file to the live posts directory
mv "$MD_FILE" "_posts/live/$CLEAN_FILENAME"
# Remove the now-empty prepub directory
rm -rf "$FULL_PATH"
# Flag for the python script step
echo "IS_BUNDLE=true" >> $GITHUB_ENV
else
# --- SINGLE FILE ROUTING LOGIC ---
mv "$FULL_PATH" "_posts/live/$CLEAN_FILENAME"
echo "IS_BUNDLE=false" >> $GITHUB_ENV
fi
# Export variables for downstream steps
echo "POST_SLUG=$CLEAN_SLUG" >> $GITHUB_ENV
echo "POST_FILENAME=$CLEAN_FILENAME" >> $GITHUB_ENV
echo "new_path=_posts/live/${CLEAN_FILENAME}" >> $GITHUB_OUTPUT
- name: Wrap Code Blocks in Raw Liquid Tags
run: python .github/scripts/wrap_code_blocks_in_raw_tags.py
- name: Rewrite Markdown Image Links
if: env.IS_BUNDLE == 'true'
run: python .github/scripts/rewrite_image_links.py
- name: Commit and Sync
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "Published: ${{ steps.process.outputs.new_path }}"
# Added assets/images/* so the bot commits the newly moved pictures
file_pattern: "_posts/live/* _posts/prepub/* assets/images/*"