Skip to content

ci(preview): publish installable PR builds - #125

Merged
Eli Bosley (elibosley) merged 5 commits into
betafrom
ci/pr-preview-actions
Jul 14, 2026
Merged

ci(preview): publish installable PR builds#125
Eli Bosley (elibosley) merged 5 commits into
betafrom
ci/pr-preview-actions

Conversation

@elibosley

@elibosley Eli Bosley (elibosley) commented Jul 14, 2026

Copy link
Copy Markdown
Member

Outcome

Adds the PR-preview infrastructure as an independent, implementation-only change so it can land before the CA UI fixes. Once merged, every opened or updated pull request can publish an installable Community Applications plugin at a stable per-PR URL and surface that URL in the pull request.

Workflows

  • Build CA PR preview runs PR code with read-only repository permissions and uploads the package and plugin manifest as an Actions artifact.
  • Publish CA PR preview runs from the trusted default branch after a successful build, validates the artifact metadata, publishes it to pr-previews/pr/<PR>/, and creates or updates one bot comment containing the installer URL.
  • Remove CA PR preview removes the published files when a pull request closes.

The comment uses a hidden marker so later builds update the existing comment rather than creating duplicates.

Build script

scripts/build-pr-preview.sh builds root-owned GNU/BSD-tar-compatible packages and generates the .plg manifest. Published installers use:

https://raw.githubusercontent.com/unraid/community.applications/pr-previews/pr/<PR>/community.applications.plg

Verification

  • actionlint .github/workflows/*.yml
  • shellcheck scripts/build-pr-preview.sh
  • bash -n scripts/build-pr-preview.sh
  • Built a test preview package and asserted its version and stable installer/package URLs.
  • PR fix(ui): refine CA cards and home rows #124's generated preview was previously installed end-to-end on Unraid 7.3.2-rc.1.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an automated pull-request preview pipeline that builds installable plugin packages, publishes them at stable per-PR paths, removes them when pull requests close, and documents installation and preview behavior.

Changes

Pull-request preview lifecycle

Layer / File(s) Summary
Preview package generation
scripts/build-pr-preview.sh
Validates inputs, stages the source, creates a .txz package, patches the plugin template, and writes preview.json metadata.
Build and publish automation
.github/workflows/pr-preview-build.yml, .github/workflows/pr-preview-publish.yml
Builds preview artifacts for pull-request updates, validates the recorded SHA, and publishes files under pr/<PR_NUMBER>/ on the pr-previews branch.
Preview cleanup and usage documentation
.github/workflows/pr-preview-cleanup.yml, docs/PR_PREVIEWS.md, plugins/CHANGES.md
Removes published previews when pull requests close and documents installation, reversion, workflow, and changelog behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PullRequest
  participant BuildCAPRPreview
  participant buildprpreview
  participant PublishCAPRPreview
  participant prpreviews
  PullRequest->>BuildCAPRPreview: opened, synchronized, or reopened
  BuildCAPRPreview->>buildprpreview: build package with PR number and head SHA
  buildprpreview-->>BuildCAPRPreview: preview artifact and preview.json
  BuildCAPRPreview->>PublishCAPRPreview: successful workflow completion
  PublishCAPRPreview->>prpreviews: validate SHA and replace pr/PR_NUMBER contents
Loading

Possibly related PRs

Poem

I built a tiny package,
With carrots tucked inside,
It hops to each PR path,
Then cleans up when closed wide.
Preview plugins dance and shine—
Squeak, test, and deploy! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title follows a conventional-commit style and clearly matches the PR’s PR-preview build and publish changes.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/pr-preview-actions
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch ci/pr-preview-actions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
scripts/build-pr-preview.sh (1)

53-78: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Specify UTF-8 encoding for file operations.

While this script primarily runs in GitHub Actions where UTF-8 is the default, relying on the system's locale encoding can cause decoding errors on different platforms (such as Windows). It is a good defensive practice to explicitly declare the encoding.

💡 Proposed refactor
-text = Path(source).read_text()
+text = Path(source).read_text(encoding="utf-8")
 replacements = {
     "version": version,
     "md5": md5,
     "pluginURL": plugin_url,
 }
 for entity, value in replacements.items():
     text, count = re.subn(
         rf'(<!ENTITY\s+{entity}\s+")[^"]*(">)',
         rf'\g<1>{value}\g<2>',
         text,
         count=1,
     )
     if count != 1:
         raise SystemExit(f"could not replace {entity} entity")
 
 text, count = re.subn(
     r'(<FILE Name="/boot/config/plugins/&name;/&name;-&version;-x86_64-1\.txz" Run="upgradepkg --install-new --reinstall">\s*<URL>)[^<]*(</URL>)',
     rf'\g<1>{package_url}\g<2>',
     text,
     count=1,
 )
 if count != 1:
     raise SystemExit("could not replace package URL")
 
-Path(destination).write_text(text)
+Path(destination).write_text(text, encoding="utf-8")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/build-pr-preview.sh` around lines 53 - 78, Specify UTF-8 encoding for
both Path.read_text and Path.write_text in the replacement flow, preserving the
existing text substitutions and error handling.
.github/workflows/pr-preview-build.yml (1)

14-14: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Disable credential persistence in checkout.

Because this job only reads code and builds an artifact without pushing changes back to the repository, you can set persist-credentials: false. This aligns with the principle of least privilege and prevents the GITHUB_TOKEN from remaining in the local .git/config file.

💡 Proposed refactor
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@v4
+        with:
+          persist-credentials: false
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/pr-preview-build.yml at line 14, Update the
actions/checkout@v4 step in the workflow to disable credential persistence by
setting persist-credentials to false.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/pr-preview-cleanup.yml:
- Around line 28-29: Update the cleanup workflow’s git commit step after staging
pr/$PR_NUMBER to check for staged differences before committing, such as with a
quiet git diff --cached guard. Exit successfully when no changes are present,
while retaining the existing commit behavior when changes are staged.

In @.github/workflows/pr-preview-publish.yml:
- Around line 31-47: Update the publish step around the PR_NUMBER validation to
add a gh pr view check using the workflow’s repository context, and exit without
publishing when the PR is no longer open; also add pull-requests: read to the
workflow permissions. Replace the wildcard cp artifact/* command with cp -a
artifact/. while preserving the existing destination and commit flow.

---

Nitpick comments:
In @.github/workflows/pr-preview-build.yml:
- Line 14: Update the actions/checkout@v4 step in the workflow to disable
credential persistence by setting persist-credentials to false.

In `@scripts/build-pr-preview.sh`:
- Around line 53-78: Specify UTF-8 encoding for both Path.read_text and
Path.write_text in the replacement flow, preserving the existing text
substitutions and error handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b1e61102-a699-4469-b31a-934f7acfd1d2

📥 Commits

Reviewing files that changed from the base of the PR and between 5cde4fe and 8e616ea.

📒 Files selected for processing (6)
  • .github/workflows/pr-preview-build.yml
  • .github/workflows/pr-preview-cleanup.yml
  • .github/workflows/pr-preview-publish.yml
  • docs/PR_PREVIEWS.md
  • plugins/CHANGES.md
  • scripts/build-pr-preview.sh

Comment thread .github/workflows/pr-preview-cleanup.yml
Comment thread .github/workflows/pr-preview-publish.yml
@elibosley

Copy link
Copy Markdown
Member Author

Applied the UTF-8 file-I/O nitpick from the CodeRabbit review body. The preview builder now explicitly reads and writes the generated manifest as UTF-8. shellcheck, bash -n, a full preview build, and manifest assertions pass.

@elibosley

Copy link
Copy Markdown
Member Author

Applied the checkout-hardening nitpick from the CodeRabbit review body. The read-only PR build now sets persist-credentials: false; the trusted publisher and cleanup checkouts retain credentials because they push to pr-previews. actionlint and git diff --check pass.

@elibosley
Eli Bosley (elibosley) changed the base branch from master to beta July 14, 2026 18:19
@elibosley
Eli Bosley (elibosley) merged commit d36f383 into beta Jul 14, 2026
2 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jul 21, 2026
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.

1 participant