mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-06-02 13:49:35 +02:00
Compare commits
2 Commits
add-script
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4b4880e0d | ||
|
|
9dc08aa8c1 |
71
.github/workflows/close-new-script-prs.yml
generated
vendored
71
.github/workflows/close-new-script-prs.yml
generated
vendored
@@ -3,7 +3,7 @@ name: Close Unauthorized New Script PRs
|
||||
on:
|
||||
pull_request_target:
|
||||
branches: ["main"]
|
||||
types: [opened, labeled]
|
||||
types: [opened, labeled, reopened, synchronize]
|
||||
|
||||
jobs:
|
||||
check-new-script:
|
||||
@@ -24,13 +24,6 @@ jobs:
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
|
||||
// --- Only act on PRs with the "new script" label ---
|
||||
const labels = pr.labels.map(l => l.name);
|
||||
if (!labels.includes("new script")) {
|
||||
core.info(`PR #${prNumber} does not have "new script" label — skipping.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// --- Allow our bots ---
|
||||
const allowedBots = [
|
||||
"push-app-to-main[bot]",
|
||||
@@ -42,38 +35,40 @@ jobs:
|
||||
return;
|
||||
}
|
||||
|
||||
// --- Check if author is a member of the contributor team ---
|
||||
const teamSlug = "contributor";
|
||||
let isMember = false;
|
||||
|
||||
try {
|
||||
const { status } = await github.rest.teams.getMembershipForUserInOrg({
|
||||
org: owner,
|
||||
team_slug: teamSlug,
|
||||
username: author,
|
||||
});
|
||||
// status 200 means the user is a member (active or pending)
|
||||
isMember = true;
|
||||
} catch (error) {
|
||||
if (error.status === 404) {
|
||||
isMember = false;
|
||||
} else {
|
||||
core.warning(`Could not check team membership for ${author}: ${error.message}`);
|
||||
// Fallback: check org membership
|
||||
try {
|
||||
await github.rest.orgs.checkMembershipForUser({
|
||||
org: owner,
|
||||
username: author,
|
||||
});
|
||||
isMember = true;
|
||||
} catch {
|
||||
isMember = false;
|
||||
}
|
||||
}
|
||||
// --- Exempt contributors via author_association ---
|
||||
// OWNER/MEMBER/COLLABORATOR are trusted; CONTRIBUTOR ("has merged before")
|
||||
// and NONE are not — their new-script PRs are still closed.
|
||||
const association = pr.author_association;
|
||||
const exempt = ["OWNER", "MEMBER", "COLLABORATOR"];
|
||||
if (exempt.includes(association)) {
|
||||
core.info(`PR #${prNumber} by ${association} "${author}" — skipping.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMember) {
|
||||
core.info(`PR #${prNumber} by contributor "${author}" — skipping.`);
|
||||
// --- Detect a new-script PR: "new script" label OR a newly-added
|
||||
// script file under ct/ install/ turnkey/ vm/ (mirrors
|
||||
// autolabeler-config.json). Removes the label-timing dependency. ---
|
||||
const labels = pr.labels.map(l => l.name);
|
||||
const hasNewScriptLabel = labels.includes("new script");
|
||||
|
||||
const scriptPrefixes = ["ct/", "install/", "turnkey/", "vm/"];
|
||||
let hasAddedScriptFile = false;
|
||||
try {
|
||||
const files = await github.paginate(github.rest.pulls.listFiles, {
|
||||
owner,
|
||||
repo,
|
||||
pull_number: prNumber,
|
||||
per_page: 100,
|
||||
});
|
||||
hasAddedScriptFile = files.some(
|
||||
f => f.status === "added" && scriptPrefixes.some(p => f.filename.startsWith(p))
|
||||
);
|
||||
} catch (error) {
|
||||
core.warning(`Could not list files for PR #${prNumber}: ${error.message}`);
|
||||
}
|
||||
|
||||
if (!hasNewScriptLabel && !hasAddedScriptFile) {
|
||||
core.info(`PR #${prNumber} is not a new-script submission (no label, no added script file) — skipping.`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
71
.github/workflows/close_issue_in_dev.yaml
generated
vendored
71
.github/workflows/close_issue_in_dev.yaml
generated
vendored
@@ -56,46 +56,57 @@ jobs:
|
||||
echo "$slugs" > pocketbase_slugs.txt
|
||||
echo "count=$(echo $slugs | wc -w)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Search for Issues with Similar Titles
|
||||
- name: Find matching issues in ProxmoxVED by slug
|
||||
id: find_issue
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
issues=$(gh issue list --repo community-scripts/ProxmoxVED --json number,title --jq '.[] | {number, title}')
|
||||
|
||||
best_match_score=0
|
||||
best_match_number=0
|
||||
|
||||
for issue in $(echo "$issues" | jq -r '. | @base64'); do
|
||||
_jq() {
|
||||
echo ${issue} | base64 --decode | jq -r ${1}
|
||||
}
|
||||
|
||||
issue_title=$(_jq '.title' | tr '[:upper:]' '[:lower:]' | sed 's/ //g' | sed 's/-//g')
|
||||
issue_number=$(_jq '.number')
|
||||
|
||||
match_score=$(echo "$title" | grep -o "$issue_title" | wc -l)
|
||||
|
||||
if [ "$match_score" -gt "$best_match_score" ]; then
|
||||
best_match_score=$match_score
|
||||
best_match_number=$issue_number
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$best_match_number" != "0" ]; then
|
||||
echo "issue_number=$best_match_number" >> $GITHUB_ENV
|
||||
else
|
||||
echo "No matching issue found."
|
||||
if [[ ! -s pocketbase_slugs.txt ]]; then
|
||||
echo "No slugs derived from PR — nothing to match."
|
||||
echo "issue_numbers=" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
slugs=$(cat pocketbase_slugs.txt)
|
||||
|
||||
- name: Comment on the Best-Matching Issue and Close It
|
||||
if: env.issue_number != ''
|
||||
# Normalize: lowercase, strip spaces and hyphens (same shape as the slug derivation)
|
||||
norm() { echo "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[[:space:]]//g; s/-//g'; }
|
||||
|
||||
issues=$(gh issue list --repo community-scripts/ProxmoxVED --state open --limit 1000 --json number,title,body)
|
||||
|
||||
matched=""
|
||||
for slug in $slugs; do
|
||||
nslug=$(norm "$slug")
|
||||
[[ -z "$nslug" ]] && continue
|
||||
while IFS= read -r row; do
|
||||
num=$(echo "$row" | jq -r '.number')
|
||||
ntitle=$(norm "$(echo "$row" | jq -r '.title')")
|
||||
body=$(echo "$row" | jq -r '.body // ""' | tr '[:upper:]' '[:lower:]')
|
||||
# Match when the issue title contains the slug, or the body mentions it verbatim
|
||||
if [[ "$ntitle" == *"$nslug"* ]] || [[ "$body" == *"$slug"* ]]; then
|
||||
matched="$matched $num"
|
||||
fi
|
||||
done < <(echo "$issues" | jq -c '.[]')
|
||||
done
|
||||
|
||||
matched=$(echo $matched | xargs -n1 2>/dev/null | sort -un | tr '\n' ' ')
|
||||
if [[ -z "$matched" ]]; then
|
||||
echo "No matching ProxmoxVED issues found for slugs: $slugs"
|
||||
echo "issue_numbers=" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
echo "Matched ProxmoxVED issues: $matched"
|
||||
echo "issue_numbers=$matched" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Comment on and close matching ProxmoxVED issues
|
||||
if: steps.find_issue.outputs.issue_numbers != ''
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.PAT_MICHEL }}
|
||||
run: |
|
||||
gh issue comment $issue_number --repo community-scripts/ProxmoxVED --body "Merged with #${{ github.event.pull_request.number }} in ProxmoxVE"
|
||||
gh issue close $issue_number --repo community-scripts/ProxmoxVED
|
||||
for issue_number in ${{ steps.find_issue.outputs.issue_numbers }}; do
|
||||
echo "Closing ProxmoxVED issue #$issue_number"
|
||||
gh issue comment "$issue_number" --repo community-scripts/ProxmoxVED --body "Merged with #${{ github.event.pull_request.number }} in ProxmoxVE"
|
||||
gh issue close "$issue_number" --repo community-scripts/ProxmoxVED
|
||||
done
|
||||
|
||||
- name: Set is_dev to false in PocketBase
|
||||
if: steps.get_slugs.outputs.count != '0'
|
||||
|
||||
4
.github/workflows/lock-issue.yaml
generated
vendored
4
.github/workflows/lock-issue.yaml
generated
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const daysBeforeLock = 3;
|
||||
const daysBeforeLock = 7;
|
||||
const lockDate = new Date();
|
||||
lockDate.setDate(lockDate.getDate() - daysBeforeLock);
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
/dependabot/i
|
||||
];
|
||||
|
||||
// Search for closed, unlocked issues older than 3 days (paginated, oldest first)
|
||||
// Search for closed, unlocked issues older than 7 days (paginated, oldest first)
|
||||
let page = 1;
|
||||
let totalLocked = 0;
|
||||
|
||||
|
||||
24
.github/workflows/pocketbase-bot.yml
generated
vendored
24
.github/workflows/pocketbase-bot.yml
generated
vendored
@@ -13,8 +13,8 @@ jobs:
|
||||
pocketbase-bot:
|
||||
runs-on: self-hosted
|
||||
|
||||
# Only act on /pocketbase commands
|
||||
if: startsWith(github.event.comment.body, '/pocketbase')
|
||||
# Act on comments that contain a /pocketbase command line (precise line check happens in-script)
|
||||
if: contains(github.event.comment.body, '/pocketbase')
|
||||
|
||||
steps:
|
||||
- name: Execute PocketBase bot command
|
||||
@@ -257,6 +257,22 @@ jobs:
|
||||
if (!res.ok) console.warn('Could not post comment:', res.body);
|
||||
}
|
||||
|
||||
// ── Locate the command line ────────────────────────────────────────
|
||||
// Accept /pocketbase at the start of ANY line (leading whitespace ok),
|
||||
// so the command works even when preceded by other text. Mid-sentence
|
||||
// mentions and blockquoted ("> ...") examples are ignored.
|
||||
const commentBody = process.env.COMMENT_BODY || '';
|
||||
const cmdLine = commentBody
|
||||
.split('\n')
|
||||
.map(l => l.trim())
|
||||
.find(l => l.startsWith('/pocketbase'));
|
||||
|
||||
if (!cmdLine) {
|
||||
console.log('No /pocketbase command line found — ignoring comment.');
|
||||
process.exit(0);
|
||||
}
|
||||
const withoutCmd = cmdLine.replace(/^\/pocketbase\s*/, '').trim();
|
||||
|
||||
// ── Permission check ───────────────────────────────────────────────
|
||||
const association = process.env.ACTOR_ASSOCIATION;
|
||||
if (association !== 'OWNER' && association !== 'MEMBER') {
|
||||
@@ -272,10 +288,6 @@ jobs:
|
||||
await addReaction('eyes');
|
||||
|
||||
// ── Parse command ──────────────────────────────────────────────────
|
||||
const commentBody = process.env.COMMENT_BODY || '';
|
||||
const lines = commentBody.trim().split('\n');
|
||||
const firstLine = lines[0].trim();
|
||||
const withoutCmd = firstLine.replace(/^\/pocketbase\s+/, '').trim();
|
||||
|
||||
function extractCodeBlock(body) {
|
||||
const m = body.match(/```[^\n]*\n([\s\S]*?)```/);
|
||||
|
||||
Reference in New Issue
Block a user