Skip to content

Commit cb0301e

Browse files
committed
workflows
1 parent 8b90b98 commit cb0301e

8 files changed

Lines changed: 244 additions & 66 deletions

.github/scripts/check-wordpress-tested-up-to.py

Lines changed: 136 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from __future__ import annotations
55

6+
import argparse
67
import json
78
import os
89
import re
@@ -32,6 +33,7 @@
3233

3334

3435
def main() -> int:
36+
args = parse_args()
3537
latest_version = get_latest_wordpress_major_minor()
3638
excluded_dirs = get_excluded_dirs()
3739
findings = find_tested_up_to_entries(excluded_dirs)
@@ -42,41 +44,54 @@ def main() -> int:
4244
write_summary(latest_version, [], [message])
4345
return 1
4446

45-
failures = []
46-
for finding in findings:
47-
if finding["version"] is None:
48-
failures.append(
49-
f"{finding['path']}:{finding['line']}: Could not parse Tested up to version."
50-
)
51-
print_github_error(
52-
"Could not parse Tested up to version.",
53-
finding["path"],
54-
finding["line"],
55-
)
56-
continue
47+
failures = get_failures(latest_version, findings)
48+
updated_paths = []
5749

58-
tested_version = normalize_major_minor(finding["version"])
59-
if tested_version != latest_version:
60-
message = (
61-
f"Tested up to is {finding['version']}; expected {latest_version} "
62-
"for the latest WordPress release."
63-
)
64-
failures.append(f"{finding['path']}:{finding['line']}: {message}")
65-
print_github_error(message, finding["path"], finding["line"])
50+
if args.fix and failures:
51+
updated_paths = update_tested_up_to_entries(findings, latest_version)
52+
findings = find_tested_up_to_entries(excluded_dirs)
53+
failures = get_failures(latest_version, findings)
54+
55+
if failures:
56+
for failure in failures:
57+
print_github_error(failure["message"], failure["path"], failure["line"])
6658

67-
write_summary(latest_version, findings, failures)
59+
write_summary(latest_version, findings, failures, updated_paths)
6860

6961
if failures:
7062
entry_label = "entry" if len(failures) == 1 else "entries"
7163
print(f"Found {len(failures)} stale or invalid Tested up to {entry_label}.")
7264
for failure in failures:
73-
print(f"- {failure}")
65+
print(f"- {format_failure(failure)}")
7466
return 1
7567

68+
if updated_paths:
69+
path_label = "file" if len(updated_paths) == 1 else "files"
70+
print(
71+
f"Updated Tested up to metadata to WordPress {latest_version} "
72+
f"in {len(updated_paths)} {path_label}."
73+
)
74+
for path in updated_paths:
75+
print(f"- {path}")
76+
return 0
77+
7678
print(f"All Tested up to entries match WordPress {latest_version}.")
7779
return 0
7880

7981

82+
def parse_args() -> argparse.Namespace:
83+
parser = argparse.ArgumentParser(
84+
description='Check WordPress "Tested up to" metadata against the latest release.'
85+
)
86+
parser.add_argument(
87+
"--fix",
88+
action="store_true",
89+
help="Update stale or invalid Tested up to entries to the latest WordPress release.",
90+
)
91+
92+
return parser.parse_args()
93+
94+
8095
def get_latest_wordpress_major_minor() -> str:
8196
if WORDPRESS_LATEST_VERSION:
8297
return normalize_major_minor(WORDPRESS_LATEST_VERSION)
@@ -175,10 +190,100 @@ def should_scan(path: Path, excluded_dirs: set[str]) -> bool:
175190
return not any(part in excluded_dirs for part in path.parts)
176191

177192

193+
def get_failures(
194+
latest_version: str,
195+
findings: list[dict[str, str | int | None]],
196+
) -> list[dict[str, str | int]]:
197+
failures = []
198+
199+
for finding in findings:
200+
if finding["version"] is None:
201+
failures.append(
202+
{
203+
"path": str(finding["path"]),
204+
"line": int(finding["line"]),
205+
"message": "Could not parse Tested up to version.",
206+
}
207+
)
208+
continue
209+
210+
tested_version = normalize_major_minor(str(finding["version"]))
211+
if tested_version != latest_version:
212+
failures.append(
213+
{
214+
"path": str(finding["path"]),
215+
"line": int(finding["line"]),
216+
"message": (
217+
f"Tested up to is {finding['version']}; expected "
218+
f"{latest_version} for the latest WordPress release."
219+
),
220+
}
221+
)
222+
223+
return failures
224+
225+
226+
def update_tested_up_to_entries(
227+
findings: list[dict[str, str | int | None]],
228+
latest_version: str,
229+
) -> list[str]:
230+
paths_to_update = {
231+
str(finding["path"])
232+
for finding in findings
233+
if finding["version"] is None
234+
or normalize_major_minor(str(finding["version"])) != latest_version
235+
}
236+
237+
for path_string in paths_to_update:
238+
path_findings = [
239+
finding for finding in findings if str(finding["path"]) == path_string
240+
]
241+
path = Path(path_string)
242+
lines = path.read_text(encoding="utf-8", errors="replace").splitlines(
243+
keepends=True
244+
)
245+
246+
for finding in path_findings:
247+
line_index = int(finding["line"]) - 1
248+
lines[line_index] = replace_tested_up_to_line(
249+
lines[line_index], latest_version
250+
)
251+
252+
path.write_text("".join(lines), encoding="utf-8")
253+
254+
return sorted(paths_to_update)
255+
256+
257+
def replace_tested_up_to_line(line: str, latest_version: str) -> str:
258+
match = TESTED_UP_TO_PATTERN.search(line)
259+
if match:
260+
return f"{line[:match.start(1)]}{latest_version}{line[match.end(1):]}"
261+
262+
label_match = TESTED_UP_TO_LABEL_PATTERN.search(line)
263+
if not label_match:
264+
return line
265+
266+
line_ending = ""
267+
content = line
268+
if line.endswith("\r\n"):
269+
content = line[:-2]
270+
line_ending = "\r\n"
271+
elif line.endswith("\n"):
272+
content = line[:-1]
273+
line_ending = "\n"
274+
275+
return f"{content[:label_match.end()]} {latest_version}{line_ending}"
276+
277+
278+
def format_failure(failure: dict[str, str | int]) -> str:
279+
return f"{failure['path']}:{failure['line']}: {failure['message']}"
280+
281+
178282
def write_summary(
179283
latest_version: str,
180284
findings: list[dict[str, str | int | None]],
181-
failures: list[str],
285+
failures: list[dict[str, str | int] | str],
286+
updated_paths: list[str] | None = None,
182287
) -> None:
183288
summary_path = os.environ.get("GITHUB_STEP_SUMMARY")
184289
if not summary_path:
@@ -194,7 +299,14 @@ def write_summary(
194299

195300
if failures:
196301
lines.append("## Failures")
197-
lines.extend(f"- {failure}" for failure in failures)
302+
lines.extend(
303+
f"- {format_failure(failure) if isinstance(failure, dict) else failure}"
304+
for failure in failures
305+
)
306+
elif updated_paths:
307+
lines.append("## Updates")
308+
lines.append(f"Updated Tested up to metadata in `{len(updated_paths)}` file(s).")
309+
lines.extend(f"- `{path}`" for path in updated_paths)
198310
else:
199311
lines.append("All Tested up to entries are current.")
200312

.github/workflows/branch-cleanup.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This workflow automatically deletes the branch associated with a pull request
22
# after it has been merged, unless the branch is protected (e.g., main, dev, staging).
3-
# It helps keep the repository clean by removing merged feature or bugfix branches.
3+
# It helps keep the repository clean by removing merged feature or bug-fix branches.
44

55
name: Branch Cleanup
66

@@ -12,6 +12,9 @@ permissions:
1212
contents: write
1313
pull-requests: read
1414

15+
env:
16+
PLUGIN_SLUG: enginescript-site-optimizer
17+
1518
jobs:
1619
cleanup:
1720
runs-on: ubuntu-latest
@@ -31,13 +34,13 @@ jobs:
3134
run: |
3235
echo "Checking branch: $BRANCH_NAME"
3336
34-
# Protected branch check - using quotes to prevent injection
37+
# Check protected branches. Quotes prevent injection.
3538
if [[ "$BRANCH_NAME" =~ ^(main|master|dev|develop|staging|production)$ ]]; then
3639
echo "::warning::Skipping deletion of protected branch: $BRANCH_NAME"
3740
exit 0
3841
fi
3942
40-
# Attempt branch deletion - using quotes to prevent injection
43+
# Attempt branch deletion. Quotes prevent injection.
4144
echo "Attempting to delete branch: $BRANCH_NAME"
4245
if git push origin --delete "$BRANCH_NAME" 2>/dev/null; then
4346
echo "::notice::Successfully deleted branch: $BRANCH_NAME"

.github/workflows/issue-management.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ permissions:
1515
pull-requests: write
1616
issues: write
1717

18+
env:
19+
PLUGIN_SLUG: enginescript-site-optimizer
20+
1821
jobs:
1922
triage:
2023
runs-on: ubuntu-latest

.github/workflows/new-issue.yml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This workflow automatically posts a guidance comment on new issues.
22
# It provides instructions to help users submit detailed information about their
3-
# WordPress environment and the issue they're experiencing with the EngineScript Site Optimizer plugin.
3+
# WordPress environment and the issue they are experiencing with EngineScript Site Optimizer.
44
# This helps maintainers diagnose and fix issues more efficiently.
55

66
name: Issue Guidance
@@ -10,9 +10,12 @@ on:
1010
types: [opened]
1111

1212
permissions:
13-
contents: write
13+
contents: read
1414
issues: write
1515

16+
env:
17+
PLUGIN_SLUG: enginescript-site-optimizer
18+
1619
jobs:
1720
guide:
1821
runs-on: ubuntu-latest
@@ -22,11 +25,11 @@ jobs:
2225
with:
2326
issue-number: ${{ github.event.issue.number }}
2427
body: |
25-
Thanks for opening an issue. Please provide a detailed description of the problem you're facing. If you have error messages or logs, please include them as well.
28+
Thanks for opening an issue. Please provide a detailed description of the problem you are seeing. If you have error messages or logs, include them as well.
2629
2730
To help us diagnose the issue, please include:
2831
- WordPress version
2932
- PHP version
30-
- List of other plugins you're using
33+
- List of other plugins you are using
3134
- Steps to reproduce the issue
32-
- What you expected to happen vs. what actually happened
35+
- What you expected to happen vs. what actually happened

.github/workflows/new-pull-request.yml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
# This workflow automatically posts a guidance comment on new pull requests.
22
# It welcomes contributors and provides a brief message to acknowledge their
3-
# contribution to the EngineScript Site Optimizer plugin.
3+
# contribution to EngineScript Site Optimizer.
44
# The workflow is triggered whenever a new pull request is opened.
55

66
name: New Pull Request Guidance
77

88
on:
9+
# pull_request_target is used only so the workflow can post this static
10+
# guidance comment on forked PRs. Do not add checkout, build, or script steps
11+
# here because this event has access to repository-scoped credentials.
912
pull_request_target:
1013
types: [opened]
1114

15+
permissions: read-all
16+
17+
env:
18+
PLUGIN_SLUG: enginescript-site-optimizer
19+
1220
jobs:
1321
guide:
1422
runs-on: ubuntu-latest
@@ -29,10 +37,10 @@ jobs:
2937
- [ ] Have you followed WordPress coding standards?
3038
- [ ] Did you update the CHANGELOG.md if needed?
3139
32-
**Security Reminder:**
33-
This plugin can handle sensitive site configuration information, so please ensure:
34-
- All user inputs are properly sanitized
35-
- All outputs are properly escaped
40+
**Security Reminder**
41+
This plugin optimizes WordPress frontend and admin performance, so please ensure:
42+
- All user input is properly sanitized
43+
- All output is properly escaped
3644
- No security vulnerabilities are introduced
3745
3846
We'll review your PR soon.

0 commit comments

Comments
 (0)