-
Notifications
You must be signed in to change notification settings - Fork 10
143 lines (123 loc) · 5.88 KB
/
Copy pathadd-article.yml
File metadata and controls
143 lines (123 loc) · 5.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
name: Add Guest Article
on:
issues:
types: [labeled]
jobs:
add-article:
if: |
github.event.label.name == 'approved' &&
contains(github.event.issue.labels.*.name, 'article')
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Parse issue and create article content file
id: parse
env:
ISSUE_BODY: ${{ github.event.issue.body }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
ISSUE_TITLE: ${{ github.event.issue.title }}
run: |
python3 - <<'PYEOF'
import os, re, datetime, yaml
# Normalize line endings — issue bodies can contain CRLF.
body = os.environ['ISSUE_BODY'].replace('\r\n', '\n').replace('\r', '\n')
def strip_html(s):
# Strip raw HTML from scalar front matter values (matches add-event.yml).
return re.sub(r'<[^>]+>', '', s).strip()
def field(label):
m = re.search(rf'### {re.escape(label)}\s+(.+?)(?=\n###|\Z)', body, re.DOTALL)
if not m:
return ''
val = m.group(1).strip()
return '' if val in ('_No response_', '') else val
title = strip_html(field('Article Title'))
author = strip_html(field('Author Name'))
description = strip_html(field('Description'))
category = strip_html(field('Category'))
tags_raw = strip_html(field('Tags (optional)'))
content = field('Article Content (Markdown)')
# The Article Content field is rendered as a ```markdown fenced block — unwrap it,
# tolerating surrounding whitespace/blank lines around the fences.
content = re.sub(r'^\s*```[a-zA-Z]*[ \t]*\n', '', content)
content = re.sub(r'\n```[ \t]*\s*$', '', content).strip()
if not title:
raise SystemExit('No article title found; aborting.')
if not content:
# A pitch with no draft — nothing to publish yet.
print('No article content provided (pitch only); skipping file creation.')
with open(os.environ['GITHUB_OUTPUT'], 'a') as out:
out.write('skip=true\n')
raise SystemExit(0)
tags = [t.strip() for t in re.split(r'[,\n]', tags_raw) if t.strip()]
today = datetime.datetime.now(datetime.timezone.utc)
date_str = today.strftime('%Y-%m-%dT%H:%M:%S+00:00')
slug = re.sub(r'[^a-z0-9]+', '-', title.lower()).strip('-')
if not slug:
# Title was only punctuation / non-ASCII — fall back to the issue number.
slug = f"article-{os.environ['ISSUE_NUMBER']}"
fm = {
'title': title,
'author': author,
'authors': [author] if author else [],
'date': date_str,
'description': description,
}
if category:
fm['categories'] = [category]
if tags:
fm['tags'] = tags
front = yaml.safe_dump(fm, default_flow_style=False, allow_unicode=True, sort_keys=False)
document = '---\n' + front + '---\n\n' + content + '\n'
year = today.strftime('%Y')
month = today.strftime('%m')
year_index = f'content/articles/{year}/_index.md'
month_index = f'content/articles/{year}/{month}/_index.md'
filepath = f'content/articles/{year}/{month}/{slug}/index.md'
if os.path.exists(filepath):
raise SystemExit(f'Article bundle already exists: {filepath}')
os.makedirs(os.path.dirname(filepath), exist_ok=True)
if not os.path.exists(year_index):
with open(year_index, 'w', encoding='utf-8') as f:
f.write(f'---\ntitle: "Articles from {year}"\ndescription: "PowerShell.org Articles published in {year}."\n---\n')
if not os.path.exists(month_index):
with open(month_index, 'w', encoding='utf-8') as f:
f.write(f'---\ntitle: "Articles from {today.strftime("%B %Y")}"\ndescription: "PowerShell.org Articles published in {today.strftime("%B %Y")}."\n---\n')
with open(filepath, 'w', encoding='utf-8') as f:
f.write(document)
with open(os.environ['GITHUB_OUTPUT'], 'a') as out:
out.write(f'skip=false\n')
out.write(f'slug={slug}\n')
out.write(f'filepath={filepath}\n')
out.write(f'article_title={title}\n')
out.write(f'year_index={year_index}\n')
out.write(f'month_index={month_index}\n')
print(f'Created {filepath}')
PYEOF
- name: Open PR
if: steps.parse.outputs.skip == 'false'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SLUG: ${{ steps.parse.outputs.slug }}
FILEPATH: ${{ steps.parse.outputs.filepath }}
YEAR_INDEX: ${{ steps.parse.outputs.year_index }}
MONTH_INDEX: ${{ steps.parse.outputs.month_index }}
ARTICLE_TITLE: ${{ steps.parse.outputs.article_title }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
run: |
BRANCH="article/issue-${ISSUE_NUMBER}-${SLUG}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git checkout -b "$BRANCH"
git add "$FILEPATH" "$YEAR_INDEX" "$MONTH_INDEX"
git commit -m "Add article: ${ARTICLE_TITLE} (closes #${ISSUE_NUMBER})"
git push origin "$BRANCH"
gh pr create \
--title "Add article: ${ARTICLE_TITLE}" \
--body "Closes #${ISSUE_NUMBER}
Auto-generated from guest blog post submission. Please review front matter and content before merging." \
--base main \
--head "$BRANCH"