diff --git a/.github/autolabeler-config.json b/.github/autolabeler-config.json index f071411a5..88d9d64c4 100644 --- a/.github/autolabeler-config.json +++ b/.github/autolabeler-config.json @@ -8,7 +8,12 @@ "turnkey/**", "vm/**" ], - "excludeGlobs": [] + "excludeGlobs": [ + "**/headers/**", + "ct/headers/**", + "tools/headers/**", + "vm/headers/**" + ] } ], "update script": [ @@ -41,7 +46,12 @@ "includeGlobs": [ "vm/**" ], - "excludeGlobs": [] + "excludeGlobs": [ + "**/headers/**", + "ct/headers/**", + "tools/headers/**", + "vm/headers/**" + ] } ], "tools": [ diff --git a/.github/workflows/close-new-script-prs.yml b/.github/workflows/close-new-script-prs.yml index 9ac26151b..acae8f577 100644 --- a/.github/workflows/close-new-script-prs.yml +++ b/.github/workflows/close-new-script-prs.yml @@ -28,6 +28,7 @@ jobs: const allowedBots = [ "push-app-to-main[bot]", "push-app-to-main", + "community-scripts-pr-app[bot]", "community-scripts-pr-app" ]; @@ -62,7 +63,9 @@ jobs: per_page: 100, }); hasAddedScriptFile = files.some( - f => f.status === "added" && scriptPrefixes.some(p => f.filename.startsWith(p)) + f => f.status === "added" && + !f.filename.includes("/headers/") && + scriptPrefixes.some(p => f.filename.startsWith(p)) ); } catch (error) { core.warning(`Could not list files for PR #${prNumber}: ${error.message}`); diff --git a/.github/workflows/pocketbase-bot.yml b/.github/workflows/pocketbase-bot.yml index 07aa56262..53a5a98bf 100644 --- a/.github/workflows/pocketbase-bot.yml +++ b/.github/workflows/pocketbase-bot.yml @@ -26,6 +26,7 @@ jobs: COMMENT_BODY: ${{ github.event.comment.body }} COMMENT_ID: ${{ github.event.comment.id }} ISSUE_NUMBER: ${{ github.event.issue.number }} + IS_PR_COMMENT: ${{ github.event.issue.pull_request && 'true' || 'false' }} REPO_OWNER: ${{ github.repository_owner }} REPO_NAME: ${{ github.event.repository.name }} ACTOR: ${{ github.event.comment.user.login }} @@ -84,6 +85,7 @@ jobs: const owner = process.env.REPO_OWNER; const repo = process.env.REPO_NAME; const issueNumber = parseInt(process.env.ISSUE_NUMBER, 10); + const isPrComment = process.env.IS_PR_COMMENT === 'true'; const commentId = parseInt(process.env.COMMENT_ID, 10); const actor = process.env.ACTOR; @@ -216,11 +218,22 @@ jobs: const prTitle = 'chore(ct): sync ' + slugValue + ' defaults with PocketBase'; const prBody = - '## Summary\n' + - '- Sync default CT variables for `' + slugValue + '` after `/pocketbase` update.\n' + - '- Updated vars: `' + updateResult.updatedVars.join('`, `') + '`.\n\n' + - '## Source\n' + - '- Triggered by @' + actor + ' via PocketBase bot.\n'; + '## ✍️ Description\n\n' + + 'Sync of the default CT variables for `' + slugValue + '` after a `/pocketbase` update by @' + actor + '.\n\n' + + 'Updated: `' + updateResult.updatedVars.join('`, `') + '`\n\n' + + '## 🔗 Related Issue\n\n' + + (isPrComment ? 'Triggered from #' : 'Fixes #') + issueNumber + '\n\n' + + '## ✅ Prerequisites (**X** in brackets)\n\n' + + '- [x] **Self-review completed** – Code follows project standards.\n' + + '- [ ] **Tested thoroughly** – Changes work as expected.\n' + + '- [x] **No security risks** – No hardcoded secrets, unnecessary privilege escalations, or permission issues.\n\n' + + '**Tested on:** not tested — generated from the PocketBase record, only `var_` defaults changed.\n\n' + + '---\n\n' + + '## 🤖 AI Assistance (**X** in brackets)\n\n' + + '- [x] **No AI used** – Scripts were written without AI assistance.\n\n' + + '---\n\n' + + '## 🛠️ Type of Change (**X** in brackets)\n\n' + + '- [x] 🐞 **Bug fix** – Resolves an issue without breaking functionality.\n'; const createPrRes = await ghRequest('/repos/' + owner + '/' + repo + '/pulls', 'POST', { title: prTitle, body: prBody, @@ -335,7 +348,10 @@ jobs: '`architectures` (amd64,arm64) `platforms` (pve,incus) ' + '`execute_in` (pve,lxc,pbs,vm,pmg,pdm) `categories` (names or ids) ' + '`type` (ct, vm, addon, …) ' + - '`is_disabled` `disable_message` `is_deleted` `deleted_message`\n\n' + + '`is_disabled` `disable_message` `is_deleted` `deleted_message` ' + + '`pin_reason` `last_update_commit`\n\n' + + 'The `var_` names from the ct scripts work too: `var_cpu` `var_ram` `var_disk`\n' + + '`var_os` `var_version` `var_port` `var_tags` `var_unprivileged`\n\n' + '**Screenshots:**\n' + '```\n' + '/pocketbase screenshot https://example.com/one.png https://example.com/two.png\n' + @@ -399,6 +415,14 @@ jobs: // ── Shared helpers ───────────────────────────────────────────────── + // The ct scripts name these var_cpu/var_ram/var_disk, and that is what + // people type. Accept them for the PocketBase keys. + const KEY_ALIASES = { + var_cpu: 'cpu', var_ram: 'ram', var_disk: 'hdd', var_hdd: 'hdd', + var_os: 'os', var_version: 'version', var_unprivileged: 'unprivileged', + var_port: 'port', var_tags: 'tags', disk: 'hdd', memory: 'ram', + }; + // Key=value parser: handles unquoted and "quoted" values function parseKVPairs(str) { const fields = {}; @@ -426,7 +450,7 @@ jobs: while (pos < str.length && !/\s/.test(str[pos])) pos++; value = str.substring(valStart, pos); } - fields[key] = value; + fields[KEY_ALIASES[key.toLowerCase()] || key] = value; } return fields; } @@ -982,6 +1006,8 @@ jobs: disable_message: 'string', is_deleted: 'boolean', deleted_message: 'string', + pin_reason: 'string', + last_update_commit: 'string', }; const parsedFields = parseKVPairs(rest);