Skip to content

Adding Site Content Automation#71

Merged
shoverbj merged 55 commits into
mainfrom
test/adding-automation
Jun 22, 2026
Merged

Adding Site Content Automation#71
shoverbj merged 55 commits into
mainfrom
test/adding-automation

Conversation

@shoverbj

Copy link
Copy Markdown
Contributor
  • Automatic blog post creation from Issue form
  • Adding new blog authors to the author list

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
scouting331site 908ad4d Commit Preview URL

Branch Preview URL
Jun 19 2026, 06:48 PM

Comment thread .github/workflows/create-blog-post.yml Fixed
Comment thread .github/workflows/process-new-authors.yml Fixed
Comment thread .github/workflows/create-blog-post.yml Fixed
Comment thread .github/workflows/create-blog-post.yml Fixed
Comment thread .github/workflows/create-doc.yml Dismissed
Comment thread .github/scripts/generate_post.py Fixed
"""

import json
import yaml
Comment on lines +22 to +46
runs-on: ubuntu-latest # Provisions a fresh virtual machine Linux runner workspace environment
outputs: # Maps global outputs from local tracking steps to make them accessible across jobs
has_new_post: ${{ steps.blog_data.outputs.has_new_post }}
title: ${{ steps.blog_data.outputs.title }}
slug: ${{ steps.blog_data.outputs.slug }}
targets: ${{ steps.blog_data.outputs.targets }} # Contains the stringified JSON target array e.g., ["TROOP_303", "PACK_303"]
steps:
- name: Checkout repository # Step 1: Fetches repository source documentation onto the runner platform
uses: actions/checkout@v4
with:
fetch-depth: 2 # Forces checking history depths of 2 commits so git diff can track HEAD~1 shifts

- name: Set up Python # Step 2: provisions Python interpreter infrastructure binaries
uses: actions/setup-python@v5
with:
python-version: '3.x' # Always downloads the latest functional patch build iteration of Python 3

- name: Parse Metadata via Python # Step 3: Run router script to identify targeting parameters
id: blog_data # Step identifier token used by outputs map fields to find variables
run: python .github/scripts/fb_router.py

# ----------------------------------------------------------------------------
# JOB 2: Run dynamic multi-process loops to dispatch entries onto Facebook Pages
# ----------------------------------------------------------------------------
facebook-routing:
Comment on lines +47 to +92
needs: parse-blog # Inter-job dependency lock: halts execution until data collection completes
# Execution gate: only runs if a post was successfully identified and targets list array contains entries
if: needs.parse-blog.outputs.has_new_post == 'true' && needs.parse-blog.outputs.targets != '[]'
runs-on: ubuntu-latest # Provisions an independent parallel system container node
strategy:
fail-fast: false # Prevent crash dependencies: keeps other unit operations processing if one page token fails
matrix:
# Converts the Python string output back into a live GitHub Actions looping engine array schema
target: ${{ fromJson(needs.parse-blog.outputs.targets) }}
steps:
- name: Set Facebook Credentials Dynamically # Step 1: Conditional evaluation mapping loop tokens to secure Vault entries
id: set_tokens # ID marker allowing the cURL step to fetch the selected dynamic parameters
run: |
TARGET="${{ matrix.target }}" # Extract current matrix iteration string item token value
if [ "$TARGET" = "TROOP_331" ]; then
echo "page_id=${{ secrets.FB_PAGE_ID_TROOP_331 }}" >> $GITHUB_OUTPUT # Maps the unique identification numbers
echo "access_token=${{ secrets.FB_ACCESS_TOKEN_TROOP_331 }}" >> $GITHUB_OUTPUT # Maps the specific system token
elif [ "$TARGET" = "PACK_303" ]; then
echo "page_id=${{ secrets.FB_PAGE_ID_PACK_303 }}" >> $GITHUB_OUTPUT
echo "access_token=${{ secrets.FB_ACCESS_TOKEN_PACK_303 }}" >> $GITHUB_OUTPUT
elif [ "$TARGET" = "CREW_303" ]; then
echo "page_id=${{ secrets.FB_PAGE_ID_CREW_303 }}" >> $GITHUB_OUTPUT
echo "access_token=${{ secrets.FB_ACCESS_TOKEN_CREW_303 }}" >> $GITHUB_OUTPUT
elif [ "$TARGET" = "TROOP_303" ]; then
echo "page_id=${{ secrets.FB_PAGE_ID_TROOP_303 }}" >> $GITHUB_OUTPUT
echo "access_token=${{ secrets.FB_ACCESS_TOKEN_TROOP_303 }}" >> $GITHUB_OUTPUT
else
echo "page_id=${{ secrets.FB_PAGE_ID_DEFAULT }}" >> $GITHUB_OUTPUT # Fallback mappings if special exceptions occur
echo "access_token=${{ secrets.FB_ACCESS_TOKEN_DEFAULT }}" >> $GITHUB_OUTPUT
fi

- name: Send Link to Selected Facebook Page # Step 2: Dispatches feed payload securely onto the Facebook Graph API endpoints
run: |
# Formulates absolute permalink layout references ensuring the /blog directory prefix matches your structure
BLOG_URL="https://brownsburgscouts.org{{ needs.parse-blog.outputs.slug }}"

# Sets up text message string template payloads using emoticons and line skip variables
MESSAGE="✍️ New Blog Post: ${{ needs.parse-blog.outputs.title }}

Read the full article here: $BLOG_URL"

# Fires cURL POST web request arguments hitting Meta Graph API servers, routing items onto dynamic destinations
curl -X POST "https://facebook.com{{ steps.set_tokens.outputs.page_id }}/feed" \
-d "message=$MESSAGE" \
-d "link=$BLOG_URL" \
-d "access_token=${{ secrets.FB_ACCESS_TOKEN_DEFAULT }}" # Authorizes operations utilizing isolated access tokens
Comment on lines +19 to +84
if: contains(github.event.issue.labels.*.name, 'blog')
runs-on: ubuntu-latest # Provisions a fresh virtual machine host environment
steps:
- name: Checkout Code # Step 1: Pulls down your repository code onto the runner
uses: actions/checkout@v6 # Uses the standard repository checkout action

- name: Generate GitHub App Token # Step 2: Obtains elevated permissions for automation steps
id: app-token # ID designation used to query output data in later fields
uses: actions/create-github-app-token@v3 # Uses GitHub App credentials to bypass workflow limits
with:
client-id: ${{ secrets.APP_ID }} # References system secret credentials
private-key: ${{ secrets.APP_PRIVATE_KEY }}

- name: Parse Issue Form # Step 3: Extracts individual form values from the issue
id: parse # ID notation used to fetch variables like jsonString
uses: stefanbuck/github-issue-parser@v3
with:
template-path: .github/ISSUE_TEMPLATE/01-new-blog-post.yml # Path targeting the source form template

- name: Set up Python # Step 4: Installs runtime environment for processing scripts
uses: actions/setup-python@v6
with:
python-version: "3.x" # Always provisions the latest minor build variation of Python 3

- name: Install Dependencies # Step 5: Installs mandatory libraries for image/text handling
run: |
python -m pip install --upgrade pip
pip install Pillow python-dateutil

- name: Process Issue Data and Assets (Python Optimizer) # Step 6: Executes data conversion script
id: process
env:
ISSUE_JSON: ${{ steps.parse.outputs.jsonString }} # Maps extracted form fields to environment variables
run: |
python .github/scripts/generate_post.py # Script execution target file

- name: Create Pull Request # Step 7: Opens a staging PR with the new post files
id: cpr # ID mapping used to fetch the PR URL for issue commenting
uses: peter-evans/create-pull-request@v8
with:
token: ${{ steps.app-token.outputs.token }} # Grants PR permissions via the generated App token
commit-message: "feat(blog): add new post from issue #${{ github.event.issue.number }}"
branch: "automation/issue-${{ github.event.issue.number }}-${{ env.BLOG_FILENAME }}" # Isolated branch path
title: "feat(blog): ${{ github.event.issue.title }}" # Sets the issue title as the PR title
body: | # Description text posted within the generated PR body description
This Pull Request was automatically generated from Issue #${{ github.event.issue.number }}.
Closes #${{ github.event.issue.number }}
delete-branch: true # Deletes the branch once the PR is merged into main
labels: | # Automatically appends tracking tags to the PR
blog

- name: Comment on Issue with PR Link # Step 8: Provides clear notification link back to the user
if: steps.cpr.outputs.pull-request-number != '' # Guard clause ensuring the PR was successfully opened
uses: peter-evans/create-or-update-comment@v5
with:
token: ${{ steps.app-token.outputs.token }}
issue-number: ${{ github.event.issue.number }}
body: | # Formats notice text targeting the native conversation section
🎉 Success! A staging branch has been created.

Your blog post is ready for review here:👉 ${{ steps.cpr.outputs.pull-request-url }}

# ----------------------------------------------------------------------------
# WORKFLOW 2: Generate Document from Issue
# ----------------------------------------------------------------------------
create-doc:
Comment on lines +86 to +151
if: contains(github.event.issue.labels.*.name, 'docs')
runs-on: ubuntu-latest # Provisions a fresh virtual machine host environment
steps:
- name: Checkout Code # Step 1: Pulls down your repository code onto the runner
uses: actions/checkout@v6

- name: Generate GitHub App Token # Step 2: Obtains elevated permissions for automation steps
id: app-token
uses: actions/create-github-app-token@v3
with:
client-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}

- name: Parse Issue Form # Step 3: Extracts individual form values from the issue
id: parse
uses: stefanbuck/github-issue-parser@v3
with:
template-path: ./github/ISSUE_TEMPLATE/02-new-document.yml # Targeting the document form template

- name: Set up Python # Step 4: Installs runtime environment for processing scripts
uses: actions/setup-python@v6
with:
python-version: "3.x"

- name: Install Dependencies # Step 5: Installs mandatory libraries for file handling
run: |
python -m pip install --upgrade pip
pip install Pillow

- name: Process Issue Data and Assets (Python Optimizer) # Step 6: Executes file conversion script
id: process
env:
ISSUE_JSON: ${{ steps.parse.outputs.jsonString }} # Maps extracted form fields to environment variables
run: |
python .github/scripts/generate_docs.py

- name: Create Pull Request # Step 7: Opens a staging PR with the new documentation files
id: cpr
uses: peter-evans/create-pull-request@v8
with:
token: ${{ steps.app-token.outputs.token }}
commit-message: "feat(docs): add new doc from issue #${{ github.event.issue.number }}"
branch: "automation/issue-${{ github.event.issue.number }}-${{ env.DOC_FILENAME }}"
title: "feat(docs): ${{ github.event.issue.title }}"
body: |
This Pull Request was automatically generated from Issue #${{ github.event.issue.number }}.
Closes #${{ github.event.issue.number }}
delete-branch: true
labels: |
docs

- name: Comment on Issue with PR Link # Step 8: Provides clear notification link back to the user
if: steps.cpr.outputs.pull-request-number != ''
uses: peter-evans/create-or-update-comment@v5
with:
token: ${{ steps.app-token.outputs.token }}
issue-number: ${{ github.event.issue.number }}
body: |
🎉 Success! A staging branch has been created.

Your document is ready for review here:👉 ${{ steps.cpr.outputs.pull-request-url }}

# ----------------------------------------------------------------------------
# WORKFLOW 3: Process New Author Request
# ----------------------------------------------------------------------------
add-author-and-pr:
Comment on lines +153 to +244
if: contains(github.event.issue.labels.*.name, 'new-author')
runs-on: ubuntu-latest # Provisions a fresh virtual machine host environment
steps:
- name: Checkout Repo # Step 1: Pulls down your repository code onto the runner
uses: actions/checkout@v6

- name: Generate Token # Step 2: Obtains elevated permissions for automation steps
id: app-token
uses: actions/create-github-app-token@v3
with:
client-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}

- name: Parse Issue Form # Step 3: Extracts profile fields from onboarding issue
id: parse
uses: stefanbuck/github-issue-parser@v3
with:
template-path: .github/ISSUE_TEMPLATE/03-new-blog-author.yml # Targeting onboarding template

- name: Set up Python # Step 4: Installs runtime environment for onboarding script
uses: actions/setup-python@v6
with:
python-version: "3.x"

- name: Install Dependencies # Step 5: Installs text/image optimization libraries
run: |
python -m pip install --upgrade pip
pip install Pillow PyYAML python-dateutil

- name: Process Author and Update Files # Step 6: Appends dataset and edits dropdown lists
id: process_files
env:
ISSUE_DATA: ${{ steps.parse.outputs.jsonString }} # Context identifier variable name target
run: |
python .github/scripts/add_author.py

- name: Create Pull Request # Step 7: Opens a staging PR updating configuration maps
if: success() # Condition check: ensures data steps finished with exit code 0
uses: peter-evans/create-pull-request@v8
with:
token: ${{ steps.app-token.outputs.token }}
commit-message: "feat: add new blog author via Issue #${{ github.event.issue.number }}"
title: "feat: add new author from Issue #${{ github.event.issue.number }}"
body: |
This PR automatically handles three tasks:
1. Downloads, optimizes, and names the avatar image matching the unique author slug.
2. Adds the new author data mapping properties into blog/authors.yml.
3. Re-generates and sorts the author dropdown options inside the issue templates.
Closes #${{ github.event.issue.number }}.
CODEOWNERS have been automatically assigned to review.
branch: "automation/issue-${{ github.event.issue.number }}"
delete-branch: true
labels: |
new-author

- name: Comment on Success # Step 8: Alerts author that review process has begun
if: success() # Condition check: executes only if PR creation succeeds
uses: peter-evans/create-or-update-comment@v5
with:
token: ${{ steps.app-token.outputs.token }}
issue-number: ${{ github.event.issue.number }}
body: |
Hi there! An automated Pull Request has been generated to add you to
the blog authors file and update our submission dropdown tools. The
project's CODEOWNERS have been notified to review and merge the
changes. Once merged, your author profile and dropdown options will
be active!

- name: Handle Duplicate / Failure # Step 9: Rejects entry and handles automated clean close
if: failure() # Condition check: executes if scripts fail (e.g., duplicate errors)
uses: actions/github-script@v9 # Leverages native JavaScript inline engine execution tools
with:
github-token: ${{ secrets.GITHUB_TOKEN }} # Standard repo token is fine for closure actions
script: | # Runs inline Javascript logic against Github API layers
const issueNumber = context.issue.number;
// Post notification error explanation comment to issue chat log
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: "🛑 Registration Error: It looks like an author profile with
this name already exists in blog/authors.yml. Duplicate entries are
not allowed. This issue will now be closed automatically."
});
// Immediately close out the issue and label it as uncompleted
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
state: 'closed',
state_reason: 'not_planned'
}); No newline at end of file
@shoverbj shoverbj merged commit 52e9e2b into main Jun 22, 2026
17 checks passed
@shoverbj shoverbj deleted the test/adding-automation branch June 22, 2026 15:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants