mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-03-10 16:14:57 +00:00
Compare commits
10 Commits
automated/
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c69c4afd25 | ||
|
|
516d8d7a0f | ||
|
|
a0c93900e9 | ||
|
|
a11f282a43 | ||
|
|
cac6b4ec59 | ||
|
|
eba96a55d2 | ||
|
|
37f4585110 | ||
|
|
e6931434b0 | ||
|
|
eec763bed0 | ||
|
|
fa62363628 |
140
.github/workflows/close_issue_in_dev.yaml
generated
vendored
140
.github/workflows/close_issue_in_dev.yaml
generated
vendored
@@ -6,14 +6,14 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
close_issue:
|
close_issue:
|
||||||
if: github.event.pull_request.merged == true && github.repository == 'community-scripts/ProxmoxVE'
|
if: github.event.pull_request.merged == true && github.repository == 'community-scripts/ProxmoxVE'
|
||||||
runs-on: ubuntu-latest
|
runs-on: self-hosted
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout target repo (main)
|
- name: Checkout target repo (merge commit)
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: community-scripts/ProxmoxVE
|
repository: community-scripts/ProxmoxVE
|
||||||
ref: main
|
ref: ${{ github.event.pull_request.merge_commit_sha }}
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Extract and Process PR Title
|
- name: Extract and Process PR Title
|
||||||
@@ -23,6 +23,39 @@ jobs:
|
|||||||
echo "Processed Title: $title"
|
echo "Processed Title: $title"
|
||||||
echo "title=$title" >> $GITHUB_ENV
|
echo "title=$title" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Get slugs from merged PR
|
||||||
|
id: get_slugs
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
pr_files=$(gh pr view ${{ github.event.pull_request.number }} --repo community-scripts/ProxmoxVE --json files -q '.files[].path' 2>/dev/null || true)
|
||||||
|
slugs=""
|
||||||
|
for path in $pr_files; do
|
||||||
|
[[ -f "$path" ]] || continue
|
||||||
|
if [[ "$path" == frontend/public/json/*.json ]]; then
|
||||||
|
s=$(jq -r '.slug // empty' "$path" 2>/dev/null)
|
||||||
|
[[ -n "$s" ]] && slugs="$slugs $s"
|
||||||
|
elif [[ "$path" == ct/*.sh ]] || [[ "$path" == install/*.sh ]] || [[ "$path" == tools/*.sh ]] || [[ "$path" == turnkey/*.sh ]] || [[ "$path" == vm/*.sh ]]; then
|
||||||
|
base=$(basename "$path" .sh)
|
||||||
|
if [[ "$path" == install/* && "$base" == *-install ]]; then
|
||||||
|
s="${base%-install}"
|
||||||
|
else
|
||||||
|
s="$base"
|
||||||
|
fi
|
||||||
|
[[ -n "$s" ]] && slugs="$slugs $s"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
slugs=$(echo $slugs | xargs -n1 | sort -u | tr '\n' ' ')
|
||||||
|
if [[ -z "$slugs" && -n "$title" ]]; then
|
||||||
|
slugs="$title"
|
||||||
|
fi
|
||||||
|
if [[ -z "$slugs" ]]; then
|
||||||
|
echo "count=0" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "$slugs" > pocketbase_slugs.txt
|
||||||
|
echo "count=$(echo $slugs | wc -w)" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Search for Issues with Similar Titles
|
- name: Search for Issues with Similar Titles
|
||||||
id: find_issue
|
id: find_issue
|
||||||
env:
|
env:
|
||||||
@@ -63,3 +96,104 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
gh issue comment $issue_number --repo community-scripts/ProxmoxVED --body "Merged with #${{ github.event.pull_request.number }} in ProxmoxVE"
|
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
|
gh issue close $issue_number --repo community-scripts/ProxmoxVED
|
||||||
|
|
||||||
|
- name: Set is_dev to false in PocketBase
|
||||||
|
if: steps.get_slugs.outputs.count != '0'
|
||||||
|
env:
|
||||||
|
POCKETBASE_URL: ${{ secrets.POCKETBASE_URL }}
|
||||||
|
POCKETBASE_COLLECTION: ${{ secrets.POCKETBASE_COLLECTION }}
|
||||||
|
POCKETBASE_ADMIN_EMAIL: ${{ secrets.POCKETBASE_ADMIN_EMAIL }}
|
||||||
|
POCKETBASE_ADMIN_PASSWORD: ${{ secrets.POCKETBASE_ADMIN_PASSWORD }}
|
||||||
|
PR_URL: ${{ github.server_url }}/${{ github.repository }}/pull/${{ github.event.pull_request.number }}
|
||||||
|
run: |
|
||||||
|
node << 'ENDSCRIPT'
|
||||||
|
(async function() {
|
||||||
|
const fs = require('fs');
|
||||||
|
const https = require('https');
|
||||||
|
const http = require('http');
|
||||||
|
const url = require('url');
|
||||||
|
|
||||||
|
function request(fullUrl, opts) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
const u = url.parse(fullUrl);
|
||||||
|
const isHttps = u.protocol === 'https:';
|
||||||
|
const body = opts.body;
|
||||||
|
const options = {
|
||||||
|
hostname: u.hostname,
|
||||||
|
port: u.port || (isHttps ? 443 : 80),
|
||||||
|
path: u.path,
|
||||||
|
method: opts.method || 'GET',
|
||||||
|
headers: opts.headers || {}
|
||||||
|
};
|
||||||
|
if (body) options.headers['Content-Length'] = Buffer.byteLength(body);
|
||||||
|
const lib = isHttps ? https : http;
|
||||||
|
const req = lib.request(options, function(res) {
|
||||||
|
let data = '';
|
||||||
|
res.on('data', function(chunk) { data += chunk; });
|
||||||
|
res.on('end', function() {
|
||||||
|
resolve({ ok: res.statusCode >= 200 && res.statusCode < 300, statusCode: res.statusCode, body: data });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
req.on('error', reject);
|
||||||
|
if (body) req.write(body);
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const raw = process.env.POCKETBASE_URL.replace(/\/$/, '');
|
||||||
|
const apiBase = /\/api$/i.test(raw) ? raw : raw + '/api';
|
||||||
|
const coll = process.env.POCKETBASE_COLLECTION;
|
||||||
|
const slugsText = fs.readFileSync('pocketbase_slugs.txt', 'utf8').trim();
|
||||||
|
const slugs = slugsText ? slugsText.split(/\s+/).filter(Boolean) : [];
|
||||||
|
if (slugs.length === 0) {
|
||||||
|
console.log('No slugs to update.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const authUrl = apiBase + '/collections/users/auth-with-password';
|
||||||
|
const authBody = JSON.stringify({
|
||||||
|
identity: process.env.POCKETBASE_ADMIN_EMAIL,
|
||||||
|
password: process.env.POCKETBASE_ADMIN_PASSWORD
|
||||||
|
});
|
||||||
|
const authRes = await request(authUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: authBody
|
||||||
|
});
|
||||||
|
if (!authRes.ok) {
|
||||||
|
throw new Error('Auth failed: ' + authRes.body);
|
||||||
|
}
|
||||||
|
const token = JSON.parse(authRes.body).token;
|
||||||
|
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
|
||||||
|
const prUrl = process.env.PR_URL || '';
|
||||||
|
|
||||||
|
for (const slug of slugs) {
|
||||||
|
const filter = "(slug='" + slug.replace(/'/g, "''") + "')";
|
||||||
|
const listRes = await request(recordsUrl + '?filter=' + encodeURIComponent(filter) + '&perPage=1', {
|
||||||
|
headers: { 'Authorization': token }
|
||||||
|
});
|
||||||
|
const list = JSON.parse(listRes.body);
|
||||||
|
const record = list.items && list.items[0];
|
||||||
|
if (!record) {
|
||||||
|
console.log('Slug not in DB, skipping: ' + slug);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const patchRes = await request(recordsUrl + '/' + record.id, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: record.name || record.slug,
|
||||||
|
last_update_commit: prUrl,
|
||||||
|
is_dev: false
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if (!patchRes.ok) {
|
||||||
|
console.warn('PATCH failed for slug ' + slug + ': ' + patchRes.body);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
console.log('Set is_dev=false for slug: ' + slug);
|
||||||
|
}
|
||||||
|
console.log('Done.');
|
||||||
|
})().catch(e => { console.error(e); process.exit(1); });
|
||||||
|
ENDSCRIPT
|
||||||
|
shell: bash
|
||||||
|
|||||||
167
.github/workflows/update-script-timestamp-on-sh-change.yml
generated
vendored
Normal file
167
.github/workflows/update-script-timestamp-on-sh-change.yml
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
name: Update script timestamp on .sh changes
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "ct/**/*.sh"
|
||||||
|
- "install/**/*.sh"
|
||||||
|
- "tools/**/*.sh"
|
||||||
|
- "turnkey/**/*.sh"
|
||||||
|
- "vm/**/*.sh"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-script-timestamp:
|
||||||
|
runs-on: self-hosted
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Get changed .sh files and derive slugs
|
||||||
|
id: slugs
|
||||||
|
run: |
|
||||||
|
changed=$(git diff --name-only "${{ github.event.before }}" "${{ github.event.after }}" -- ct/ install/ tools/ turnkey/ vm/ | grep '\.sh$' || true)
|
||||||
|
if [[ -z "$changed" ]]; then
|
||||||
|
echo "No .sh files changed in ct/, install/, tools/, turnkey/, or vm/."
|
||||||
|
echo "count=0" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
declare -A seen
|
||||||
|
slugs=""
|
||||||
|
for f in $changed; do
|
||||||
|
[[ -f "$f" ]] || continue
|
||||||
|
base="${f##*/}"
|
||||||
|
base="${base%.sh}"
|
||||||
|
if [[ "$f" == install/* && "$base" == *-install ]]; then
|
||||||
|
slug="${base%-install}"
|
||||||
|
else
|
||||||
|
slug="$base"
|
||||||
|
fi
|
||||||
|
if [[ -z "${seen[$slug]:-}" ]]; then
|
||||||
|
seen[$slug]=1
|
||||||
|
slugs="$slugs $slug"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
slugs=$(echo $slugs | xargs -n1 | sort -u)
|
||||||
|
if [[ -z "$slugs" ]]; then
|
||||||
|
echo "No slugs to update."
|
||||||
|
echo "count=0" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "$slugs" > changed_slugs.txt
|
||||||
|
echo "count=$(echo "$slugs" | wc -w)" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Parse PR number from merge commit
|
||||||
|
id: pr
|
||||||
|
run: |
|
||||||
|
re='#([0-9]+)'
|
||||||
|
if [[ "$COMMIT_MSG" =~ $re ]]; then
|
||||||
|
echo "number=${BASH_REMATCH[1]}" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "number=" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
COMMIT_MSG: ${{ github.event.head_commit.message }}
|
||||||
|
|
||||||
|
- name: Update script timestamps in PocketBase
|
||||||
|
if: steps.slugs.outputs.count != '0'
|
||||||
|
env:
|
||||||
|
POCKETBASE_URL: ${{ secrets.POCKETBASE_URL }}
|
||||||
|
POCKETBASE_COLLECTION: ${{ secrets.POCKETBASE_COLLECTION }}
|
||||||
|
POCKETBASE_ADMIN_EMAIL: ${{ secrets.POCKETBASE_ADMIN_EMAIL }}
|
||||||
|
POCKETBASE_ADMIN_PASSWORD: ${{ secrets.POCKETBASE_ADMIN_PASSWORD }}
|
||||||
|
COMMIT_URL: ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}
|
||||||
|
PR_URL: ${{ steps.pr.outputs.number != '' && format('{0}/{1}/pull/{2}', github.server_url, github.repository, steps.pr.outputs.number) || '' }}
|
||||||
|
run: |
|
||||||
|
node << 'ENDSCRIPT'
|
||||||
|
(async function() {
|
||||||
|
const fs = require('fs');
|
||||||
|
const https = require('https');
|
||||||
|
const http = require('http');
|
||||||
|
const url = require('url');
|
||||||
|
|
||||||
|
function request(fullUrl, opts) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
const u = url.parse(fullUrl);
|
||||||
|
const isHttps = u.protocol === 'https:';
|
||||||
|
const body = opts.body;
|
||||||
|
const options = {
|
||||||
|
hostname: u.hostname,
|
||||||
|
port: u.port || (isHttps ? 443 : 80),
|
||||||
|
path: u.path,
|
||||||
|
method: opts.method || 'GET',
|
||||||
|
headers: opts.headers || {}
|
||||||
|
};
|
||||||
|
if (body) options.headers['Content-Length'] = Buffer.byteLength(body);
|
||||||
|
const lib = isHttps ? https : http;
|
||||||
|
const req = lib.request(options, function(res) {
|
||||||
|
let data = '';
|
||||||
|
res.on('data', function(chunk) { data += chunk; });
|
||||||
|
res.on('end', function() {
|
||||||
|
resolve({ ok: res.statusCode >= 200 && res.statusCode < 300, statusCode: res.statusCode, body: data });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
req.on('error', reject);
|
||||||
|
if (body) req.write(body);
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const raw = process.env.POCKETBASE_URL.replace(/\/$/, '');
|
||||||
|
const apiBase = /\/api$/i.test(raw) ? raw : raw + '/api';
|
||||||
|
const coll = process.env.POCKETBASE_COLLECTION;
|
||||||
|
const slugsText = fs.readFileSync('changed_slugs.txt', 'utf8').trim();
|
||||||
|
const slugs = slugsText ? slugsText.split(/\s+/).filter(Boolean) : [];
|
||||||
|
if (slugs.length === 0) {
|
||||||
|
console.log('No slugs to update.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const authUrl = apiBase + '/collections/users/auth-with-password';
|
||||||
|
const authBody = JSON.stringify({
|
||||||
|
identity: process.env.POCKETBASE_ADMIN_EMAIL,
|
||||||
|
password: process.env.POCKETBASE_ADMIN_PASSWORD
|
||||||
|
});
|
||||||
|
const authRes = await request(authUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: authBody
|
||||||
|
});
|
||||||
|
if (!authRes.ok) {
|
||||||
|
throw new Error('Auth failed: ' + authRes.body);
|
||||||
|
}
|
||||||
|
const token = JSON.parse(authRes.body).token;
|
||||||
|
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
|
||||||
|
|
||||||
|
for (const slug of slugs) {
|
||||||
|
const filter = "(slug='" + slug.replace(/'/g, "''") + "')";
|
||||||
|
const listRes = await request(recordsUrl + '?filter=' + encodeURIComponent(filter) + '&perPage=1', {
|
||||||
|
headers: { 'Authorization': token }
|
||||||
|
});
|
||||||
|
const list = JSON.parse(listRes.body);
|
||||||
|
const record = list.items && list.items[0];
|
||||||
|
if (!record) {
|
||||||
|
console.log('Slug not in DB, skipping: ' + slug);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const patchRes = await request(recordsUrl + '/' + record.id, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: record.name || record.slug,
|
||||||
|
last_update_commit: process.env.PR_URL || process.env.COMMIT_URL || ''
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if (!patchRes.ok) {
|
||||||
|
console.warn('PATCH failed for slug ' + slug + ': ' + patchRes.body);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
console.log('Updated timestamp for slug: ' + slug);
|
||||||
|
}
|
||||||
|
console.log('Done.');
|
||||||
|
})().catch(e => { console.error(e); process.exit(1); });
|
||||||
|
ENDSCRIPT
|
||||||
|
shell: bash
|
||||||
@@ -422,6 +422,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
|||||||
|
|
||||||
## 2026-03-10
|
## 2026-03-10
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- [Fix] Immich: Pin libvips to 8.17.3 [@vhsdream](https://github.com/vhsdream) ([#12744](https://github.com/community-scripts/ProxmoxVE/pull/12744))
|
||||||
|
|
||||||
## 2026-03-09
|
## 2026-03-09
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
### 🚀 Updated Scripts
|
||||||
|
|||||||
@@ -380,7 +380,7 @@ function compile_imagemagick() {
|
|||||||
|
|
||||||
function compile_libvips() {
|
function compile_libvips() {
|
||||||
SOURCE=$SOURCE_DIR/libvips
|
SOURCE=$SOURCE_DIR/libvips
|
||||||
: "${LIBVIPS_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/libvips.json)}"
|
LIBVIPS_REVISION="0c9151a4f416d2f8ae20a755db218f6637050eec"
|
||||||
if [[ "$LIBVIPS_REVISION" != "$(grep 'libvips' ~/.immich_library_revisions | awk '{print $2}')" ]]; then
|
if [[ "$LIBVIPS_REVISION" != "$(grep 'libvips' ~/.immich_library_revisions | awk '{print $2}')" ]]; then
|
||||||
msg_info "Recompiling libvips"
|
msg_info "Recompiling libvips"
|
||||||
[[ -d "$SOURCE" ]] && rm -rf "$SOURCE"
|
[[ -d "$SOURCE" ]] && rm -rf "$SOURCE"
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ export const navbarLinks = [
|
|||||||
export const mostPopularScripts = ["post-pve-install", "docker", "homeassistant"];
|
export const mostPopularScripts = ["post-pve-install", "docker", "homeassistant"];
|
||||||
|
|
||||||
export const analytics = {
|
export const analytics = {
|
||||||
url: "analytics.bramsuurd.nl",
|
url: "analytics.community-scripts.org",
|
||||||
token: "f9eee289f931",
|
token: "e9f14e1e7232",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AlertColors = {
|
export const AlertColors = {
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ msg_ok "(4/5) Compiled imagemagick"
|
|||||||
|
|
||||||
msg_info "(5/5) Compiling libvips"
|
msg_info "(5/5) Compiling libvips"
|
||||||
SOURCE=$SOURCE_DIR/libvips
|
SOURCE=$SOURCE_DIR/libvips
|
||||||
: "${LIBVIPS_REVISION:=$(jq -cr '.revision' $BASE_DIR/server/sources/libvips.json)}"
|
LIBVIPS_REVISION="0c9151a4f416d2f8ae20a755db218f6637050eec"
|
||||||
$STD git clone https://github.com/libvips/libvips.git "$SOURCE"
|
$STD git clone https://github.com/libvips/libvips.git "$SOURCE"
|
||||||
cd "$SOURCE"
|
cd "$SOURCE"
|
||||||
$STD git reset --hard "$LIBVIPS_REVISION"
|
$STD git reset --hard "$LIBVIPS_REVISION"
|
||||||
|
|||||||
Reference in New Issue
Block a user