Skip to content

Add scheduled workflow to update all plugins daily#7406

Merged
JohnMcLear merged 1 commit into
ether:developfrom
JohnMcLear:feat/scheduled-plugin-updates
Mar 31, 2026
Merged

Add scheduled workflow to update all plugins daily#7406
JohnMcLear merged 1 commit into
ether:developfrom
JohnMcLear:feat/scheduled-plugin-updates

Conversation

@JohnMcLear

Copy link
Copy Markdown
Member

Summary

  • Adds a GitHub Actions workflow that runs daily at 06:00 UTC
  • Clones all ether/ep_* repos and runs checkPlugin autopush on each
  • Updates workflows, dependencies (including pnpm update), linting, and version bumps
  • Can also be triggered manually via workflow_dispatch

Setup required

Create a PLUGINS_PAT org secret at https://github.com/organizations/ether/settings/secrets/actions with a Personal Access Token that has push access to all ether/ep_* repos (needs repo scope or fine-grained with contents write access to the ether org).

Test plan

  • Create PLUGINS_PAT secret
  • Trigger workflow manually to verify it works
  • Verify plugins get updated commits

🤖 Generated with Claude Code

Runs checkPlugin with autopush on all ether/ep_* repos daily at
06:00 UTC. Updates workflows, dependencies, linting, and version
bumps across all plugins.

Requires PLUGINS_PAT org secret with push access to all ep_* repos.
Can also be triggered manually via workflow_dispatch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Review Summary by Qodo

Add scheduled workflow to update all plugins daily

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Adds GitHub Actions workflow for daily automated plugin updates
• Runs checkPlugin autopush on all ether/ep_* repositories daily at 06:00 UTC
• Supports manual triggering via workflow_dispatch for on-demand updates
• Requires PLUGINS_PAT organization secret with push access to plugin repos
Diagram
flowchart LR
  schedule["Daily Schedule<br/>06:00 UTC"] --> workflow["Update Plugins<br/>Workflow"]
  manual["Manual Trigger<br/>workflow_dispatch"] --> workflow
  workflow --> setup["Setup Environment<br/>Node.js, pnpm"]
  setup --> git["Configure Git<br/>with PAT"]
  git --> list["List all ep_*<br/>Repositories"]
  list --> loop["Clone/Pull &<br/>checkPlugin autopush"]
  loop --> result["Update Commits<br/>Pushed to Repos"]
Loading

Grey Divider

File Changes

1. .github/workflows/update-plugins.yml ✨ Enhancement +63/-0

Daily automated plugin update workflow

• Creates new GitHub Actions workflow triggered daily at 06:00 UTC and manually via
 workflow_dispatch
• Sets up Node.js 22 and pnpm 10 environment with necessary dependencies
• Configures git authentication using PLUGINS_PAT secret for accessing ether organization
 repositories
• Iterates through all ether/ep_* repositories, cloning/pulling them, and running checkPlugin
 with autopush flag to automatically update workflows, dependencies, linting, and version bumps

.github/workflows/update-plugins.yml


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Mar 31, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (5) 📘 Rule violations (1) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Scheduled workflow runs by default 📘 Rule violation ☼ Reliability
Description
The new workflow is enabled on a daily cron schedule, changing default behavior without an
enable/disable mechanism. This violates the requirement that new features be gated behind a feature
flag and disabled by default.
Code

.github/workflows/update-plugins.yml[R3-6]

+on:
+  schedule:
+    - cron: '0 6 * * *'  # Daily at 06:00 UTC
+  workflow_dispatch:  # Allow manual trigger
Evidence
PR Compliance ID 9 requires new features to be behind a feature flag and disabled by default. The
workflow adds a schedule trigger (cron) that will run automatically every day after merge, and
it performs autopush updates, so the feature is enabled by default.

.github/workflows/update-plugins.yml[3-6]
.github/workflows/update-plugins.yml[59-62]
Best Practice: Repository guidelines

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The scheduled GitHub Actions workflow is enabled by default via `on.schedule`, which introduces new automatic behavior without a feature flag.

## Issue Context
The workflow performs automated plugin updates with `autopush`, so it should be explicitly enabled (disabled by default) to comply with the feature-flag requirement.

## Fix Focus Areas
- .github/workflows/update-plugins.yml[3-6]
- .github/workflows/update-plugins.yml[35-63]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Pipeline hides failures 🐞 Bug ≡ Correctness
Description
The checkPlugin command is piped to tail, so the workflow step uses tail’s exit code and can
report success even when checkPlugin fails for a plugin. This can silently skip updates/pushes
while still printing only the last 20 lines of output.
Code

.github/workflows/update-plugins.yml[R60-61]

+            cd etherpad-lite/bin
+            pnpm run checkPlugin "$plugin" autopush 2>&1 | tail -20 || echo "WARN: checkPlugin failed for $plugin"
Evidence
In the workflow, pnpm run checkPlugin ... | tail -20 makes the pipeline exit status come from
tail, not the pnpm/Node process, so failures thrown by checkPlugin won’t necessarily fail the
step. The checkPlugin script exits 0 only on successful completion; otherwise it throws/errors (so
callers must preserve its exit status).

.github/workflows/update-plugins.yml[59-62]
bin/plugins/checkPlugin.ts[13-16]
bin/plugins/checkPlugin.ts[483-485]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The workflow pipes `pnpm run checkPlugin ...` into `tail`, which masks `checkPlugin` failures because the pipeline exit code becomes `tail`'s exit code.

### Issue Context
`bin/plugins/checkPlugin.ts` is designed to fail the process on errors (throws/unhandled rejection) and only calls `process.exit(0)` on success. The workflow should therefore propagate the actual command exit status.

### Fix Focus Areas
- .github/workflows/update-plugins.yml[59-62]

### Suggested fix
- Add `set -euo pipefail` at the start of the run block.
- Replace the pipeline with an approach that keeps the original exit code, e.g.:
 - Capture output and status:
   - `out=$(pnpm run checkPlugin "$plugin" autopush 2>&1); status=$?; echo "$out" | tail -20; [ $status -eq 0 ] || { echo "WARN: ..."; continue; }`
 - Or use `tee` plus `PIPESTATUS[0]` under bash with `pipefail`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Repo list truncation 🐞 Bug ≡ Correctness
Description
The workflow only lists the first 200 repos from the ether org, so any additional ep_* repos
beyond that will never be processed. This breaks the stated goal of updating all ether/ep_*
plugins daily.
Code

.github/workflows/update-plugins.yml[44]

+          plugins=$(gh repo list ether --limit 200 --json name --jq '.[] | select(.name | startswith("ep_")) | .name')
Evidence
The workflow hard-caps enumeration at --limit 200. Existing repo scripts/docs already use
per_page=1000 and multiple pages when enumerating ep_* repos, indicating pagination/high limits
are expected for completeness.

.github/workflows/update-plugins.yml[43-45]
bin/plugins/updateAllPluginsScript.sh[1-5]
bin/plugins/README.md[41-51]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The workflow enumerates repos with `gh repo list ... --limit 200`, which can omit `ep_*` repos beyond the first 200.

### Issue Context
This workflow intends to update *all* `ether/ep_*` repos. Existing scripts in `bin/plugins/` already show multi-page enumeration patterns.

### Fix Focus Areas
- .github/workflows/update-plugins.yml[43-45]

### Suggested fix
Use a paginated API call instead of a fixed limit, for example:
- `plugins=$(gh api --paginate 'orgs/ether/repos?per_page=100' --jq '.[].name | select(startswith("ep_"))')`
Or raise the limit to a sufficiently high value *and* confirm it truly covers all repos.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
4. Core repo not excluded 🐞 Bug ≡ Correctness
Description
The workflow processes every repo whose name starts with ep_ without excluding ep_etherpad-lite,
which existing plugin automation explicitly skips. If ep_etherpad-lite is present in the org, this
workflow could create automated commits/pushes to that repo unintentionally.
Code

.github/workflows/update-plugins.yml[R44-46]

+          plugins=$(gh repo list ether --limit 200 --json name --jq '.[] | select(.name | startswith("ep_")) | .name')
+
+          for plugin in $plugins; do
Evidence
The jq filter selects any repo whose name starts with ep_ and the loop runs `checkPlugin ...
autopush for each. Existing repo automation explicitly excludes ep_etherpad-lite`, demonstrating
intended behavior that this workflow currently lacks.

.github/workflows/update-plugins.yml[44-46]
bin/plugins/updateAllPluginsScript.sh[11-14]
bin/plugins/README.md[47-50]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The workflow processes every `ep_*` repo and does not skip `ep_etherpad-lite`, unlike existing plugin automation.

### Issue Context
`checkPlugin` with `autopush` can modify files, commit, and push. Existing scripts/docs treat `ep_etherpad-lite` as a special-case repo to skip.

### Fix Focus Areas
- .github/workflows/update-plugins.yml[44-46]

### Suggested fix
Add an explicit exclusion in the filter or in the loop, e.g.:
- In jq: `select(.name | startswith("ep_") and .name != "ep_etherpad-lite")`
- Or in bash: `[[ "$plugin" == "ep_etherpad-lite" ]] && continue`

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

5. Missing PAT not detected 🐞 Bug ☼ Reliability
Description
If secrets.PLUGINS_PAT is unset, the workflow still configures git URL rewriting with an empty
token and proceeds until clone/push operations fail. This causes avoidable late failures instead of
a clear, early error.
Code

.github/workflows/update-plugins.yml[R36-44]

+        env:
+          GH_TOKEN: ${{ secrets.PLUGINS_PAT }}
+        run: |
+          # Configure git to use the PAT for all ether/ repos
+          git config --global url."https://x-access-token:${GH_TOKEN}@github.com/ether/".insteadOf "https://github.com/ether/"
+
+          cd ..
+          # List all ep_* repos from ether org
+          plugins=$(gh repo list ether --limit 200 --json name --jq '.[] | select(.name | startswith("ep_")) | .name')
Evidence
The workflow directly uses ${{ secrets.PLUGINS_PAT }} to build the rewritten URL and does not
validate that GH_TOKEN is non-empty before proceeding to gh repo list and git clone/push
operations.

.github/workflows/update-plugins.yml[36-45]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The workflow does not validate that `PLUGINS_PAT` is present before using it in git URL rewriting.

### Issue Context
On manual runs in environments without secrets (or misconfiguration), this will fail later during cloning/pushing rather than producing a clear upfront error.

### Fix Focus Areas
- .github/workflows/update-plugins.yml[36-41]

### Suggested fix
Add an early guard in the run script, e.g.:
- `: "${GH_TOKEN:?PLUGINS_PAT secret is required}"`
Or:
- `if [ -z "${GH_TOKEN:-}" ]; then echo "::error::PLUGINS_PAT is not set"; exit 1; fi`

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

6. Unpinned action versions 🐞 Bug ⛨ Security
Description
The workflow uses actions by major version tags (e.g., @v4) rather than pinned commit SHAs, which
increases supply-chain risk for a scheduled workflow running with a high-privilege PAT. While not a
functional bug, it is a meaningful security hardening gap.
Code

.github/workflows/update-plugins.yml[R12-24]

+      - name: Check out etherpad-lite
+        uses: actions/checkout@v4
+
+      - uses: pnpm/action-setup@v3
+        name: Install pnpm
+        with:
+          version: 10
+          run_install: false
+
+      - name: Use Node.js
+        uses: actions/setup-node@v4
+        with:
+          node-version: 22
Evidence
The workflow references third-party actions by mutable tags. Pinning to a full commit SHA is a
standard GitHub Actions hardening recommendation, especially for workflows that run on a schedule
with access to secrets.

.github/workflows/update-plugins.yml[12-24]
Best Practice: GitHub Actions Security Hardening

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Actions are referenced by version tags rather than commit SHAs.

### Issue Context
This workflow runs on a schedule and uses a PAT capable of pushing to many repositories.

### Fix Focus Areas
- .github/workflows/update-plugins.yml[12-24]

### Suggested fix
Replace `uses: <action>@vX` with `uses: <action>@<full_commit_sha>` for each action, and optionally document the pinned SHAs (and how/when to update them).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +10 to +63
runs-on: ubuntu-latest
steps:
- name: Check out etherpad-lite
uses: actions/checkout@v4

- uses: pnpm/action-setup@v3
name: Install pnpm
with:
version: 10
run_install: false

- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 22

- name: Install bin dependencies
working-directory: ./bin
run: pnpm install

- name: Configure git
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com'

- name: Clone and update all plugins
env:
GH_TOKEN: ${{ secrets.PLUGINS_PAT }}
run: |
# Configure git to use the PAT for all ether/ repos
git config --global url."https://x-access-token:${GH_TOKEN}@github.com/ether/".insteadOf "https://github.com/ether/"

cd ..
# List all ep_* repos from ether org
plugins=$(gh repo list ether --limit 200 --json name --jq '.[] | select(.name | startswith("ep_")) | .name')

for plugin in $plugins; do
echo "============================================================"
echo "Processing $plugin"
echo "============================================================"

# Clone if not present
if [ ! -d "$plugin" ]; then
git clone "https://github.com/ether/${plugin}.git" "$plugin" || { echo "SKIP: clone failed"; continue; }
fi

# Pull latest
(cd "$plugin" && git pull --ff-only) || { echo "SKIP: pull failed"; continue; }

# Run checkPlugin with autopush
cd etherpad-lite/bin
pnpm run checkPlugin "$plugin" autopush 2>&1 | tail -20 || echo "WARN: checkPlugin failed for $plugin"
cd ../..
done

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
Comment on lines +3 to +6
on:
schedule:
- cron: '0 6 * * *' # Daily at 06:00 UTC
workflow_dispatch: # Allow manual trigger

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Scheduled workflow runs by default 📘 Rule violation ☼ Reliability

The new workflow is enabled on a daily cron schedule, changing default behavior without an
enable/disable mechanism. This violates the requirement that new features be gated behind a feature
flag and disabled by default.
Agent Prompt
## Issue description
The scheduled GitHub Actions workflow is enabled by default via `on.schedule`, which introduces new automatic behavior without a feature flag.

## Issue Context
The workflow performs automated plugin updates with `autopush`, so it should be explicitly enabled (disabled by default) to comply with the feature-flag requirement.

## Fix Focus Areas
- .github/workflows/update-plugins.yml[3-6]
- .github/workflows/update-plugins.yml[35-63]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +60 to +61
cd etherpad-lite/bin
pnpm run checkPlugin "$plugin" autopush 2>&1 | tail -20 || echo "WARN: checkPlugin failed for $plugin"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Pipeline hides failures 🐞 Bug ≡ Correctness

The checkPlugin command is piped to tail, so the workflow step uses tail’s exit code and can
report success even when checkPlugin fails for a plugin. This can silently skip updates/pushes
while still printing only the last 20 lines of output.
Agent Prompt
### Issue description
The workflow pipes `pnpm run checkPlugin ...` into `tail`, which masks `checkPlugin` failures because the pipeline exit code becomes `tail`'s exit code.

### Issue Context
`bin/plugins/checkPlugin.ts` is designed to fail the process on errors (throws/unhandled rejection) and only calls `process.exit(0)` on success. The workflow should therefore propagate the actual command exit status.

### Fix Focus Areas
- .github/workflows/update-plugins.yml[59-62]

### Suggested fix
- Add `set -euo pipefail` at the start of the run block.
- Replace the pipeline with an approach that keeps the original exit code, e.g.:
  - Capture output and status:
    - `out=$(pnpm run checkPlugin "$plugin" autopush 2>&1); status=$?; echo "$out" | tail -20; [ $status -eq 0 ] || { echo "WARN: ..."; continue; }`
  - Or use `tee` plus `PIPESTATUS[0]` under bash with `pipefail`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


cd ..
# List all ep_* repos from ether org
plugins=$(gh repo list ether --limit 200 --json name --jq '.[] | select(.name | startswith("ep_")) | .name')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Repo list truncation 🐞 Bug ≡ Correctness

The workflow only lists the first 200 repos from the ether org, so any additional ep_* repos
beyond that will never be processed. This breaks the stated goal of updating all ether/ep_*
plugins daily.
Agent Prompt
### Issue description
The workflow enumerates repos with `gh repo list ... --limit 200`, which can omit `ep_*` repos beyond the first 200.

### Issue Context
This workflow intends to update *all* `ether/ep_*` repos. Existing scripts in `bin/plugins/` already show multi-page enumeration patterns.

### Fix Focus Areas
- .github/workflows/update-plugins.yml[43-45]

### Suggested fix
Use a paginated API call instead of a fixed limit, for example:
- `plugins=$(gh api --paginate 'orgs/ether/repos?per_page=100' --jq '.[].name | select(startswith("ep_"))')`
Or raise the limit to a sufficiently high value *and* confirm it truly covers all repos.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +44 to +46
plugins=$(gh repo list ether --limit 200 --json name --jq '.[] | select(.name | startswith("ep_")) | .name')

for plugin in $plugins; do

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Core repo not excluded 🐞 Bug ≡ Correctness

The workflow processes every repo whose name starts with ep_ without excluding ep_etherpad-lite,
which existing plugin automation explicitly skips. If ep_etherpad-lite is present in the org, this
workflow could create automated commits/pushes to that repo unintentionally.
Agent Prompt
### Issue description
The workflow processes every `ep_*` repo and does not skip `ep_etherpad-lite`, unlike existing plugin automation.

### Issue Context
`checkPlugin` with `autopush` can modify files, commit, and push. Existing scripts/docs treat `ep_etherpad-lite` as a special-case repo to skip.

### Fix Focus Areas
- .github/workflows/update-plugins.yml[44-46]

### Suggested fix
Add an explicit exclusion in the filter or in the loop, e.g.:
- In jq: `select(.name | startswith("ep_") and .name != "ep_etherpad-lite")`
- Or in bash: `[[ "$plugin" == "ep_etherpad-lite" ]] && continue`

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@JohnMcLear JohnMcLear merged commit f9798cf into ether:develop Mar 31, 2026
24 checks passed
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