mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2025-11-04 18:32:51 +00:00
Compare commits
1 Commits
update_ver
...
testing_ac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34032b7be3 |
458
.github/AUTOLABELER_FEATURES.md
generated
vendored
Normal file
458
.github/AUTOLABELER_FEATURES.md
generated
vendored
Normal file
@@ -0,0 +1,458 @@
|
|||||||
|
# 🤖 Autolabeler Features
|
||||||
|
|
||||||
|
This document describes the automated features of our PR labeling system.
|
||||||
|
|
||||||
|
## 🎯 All Features
|
||||||
|
|
||||||
|
### 1. **Label Cleanup** ✨
|
||||||
|
|
||||||
|
Automatically removes outdated or conflicting labels when PR is updated.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
- PR initially labeled with `feature` and `bugfix`
|
||||||
|
- User updates PR and only checks `bugfix`
|
||||||
|
- Bot removes `feature` label automatically
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
|
||||||
|
- Prevents label confusion
|
||||||
|
- Ensures accurate changelog categorization
|
||||||
|
- Maintains label consistency
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. **Commit Message Analysis** 📝
|
||||||
|
|
||||||
|
Automatically detects change types from conventional commit messages.
|
||||||
|
|
||||||
|
**Supported Formats:**
|
||||||
|
|
||||||
|
- `fix:` or `fix(scope):` → adds `bugfix` label
|
||||||
|
- `feat:` or `feat(scope):` → adds `feature` label
|
||||||
|
- `refactor:` or `refactor(scope):` → adds `refactor` label
|
||||||
|
- `BREAKING CHANGE:` or `feat!:` → adds `breaking change` label
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```
|
||||||
|
feat(docker): add support for custom networks
|
||||||
|
|
||||||
|
This adds support for user-defined networks
|
||||||
|
```
|
||||||
|
|
||||||
|
→ Automatically labeled with `feature`
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
|
||||||
|
- Works even if checkboxes are forgotten
|
||||||
|
- Supports standard Git conventions
|
||||||
|
- Combines with template checkboxes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. **Size Labels** 📏
|
||||||
|
|
||||||
|
Automatically adds size labels based on total lines changed.
|
||||||
|
|
||||||
|
**Size Categories:**
|
||||||
|
|
||||||
|
- `size: XS` → 1-10 lines (🟢 Green)
|
||||||
|
- `size: S` → 11-50 lines (🟢 Yellow-Green)
|
||||||
|
- `size: M` → 51-200 lines (🟡 Yellow)
|
||||||
|
- `size: L` → 201-500 lines (🟠 Orange)
|
||||||
|
- `size: XL` → 500+ lines (🔴 Red)
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
|
||||||
|
- Helps reviewers prioritize
|
||||||
|
- Quick visual indication of PR complexity
|
||||||
|
- Automatic and consistent
|
||||||
|
|
||||||
|
**Note:** Labels need to be created in repository first. See [SETUP_NEW_LABELS.md](SETUP_NEW_LABELS.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. **First-Time Contributor Welcome** 🎉
|
||||||
|
|
||||||
|
Special welcome message for contributors making their first PR.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 🎉 Welcome to the Community!
|
||||||
|
|
||||||
|
Thank you @username for your first contribution! 🙌
|
||||||
|
|
||||||
|
A maintainer will review your PR soon. Here are some helpful resources:
|
||||||
|
|
||||||
|
- Contributing Guide
|
||||||
|
- Code of Conduct
|
||||||
|
```
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
|
||||||
|
- Better onboarding experience
|
||||||
|
- Increases contributor retention
|
||||||
|
- Builds community
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. **Documentation Check** 📚
|
||||||
|
|
||||||
|
Warns when code changes don't include documentation updates.
|
||||||
|
|
||||||
|
**Triggers Warning When:**
|
||||||
|
|
||||||
|
- Code files modified (`.sh`, `.func`, `.js`, `.go`, etc.)
|
||||||
|
- No documentation files modified (`.md`, `README`, etc.)
|
||||||
|
- Not a bugfix or refactor (features should have docs!)
|
||||||
|
|
||||||
|
**Example Warning:**
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
📚 **Documentation update recommended**: Consider updating documentation
|
||||||
|
for these code changes.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
|
||||||
|
- Improves documentation coverage
|
||||||
|
- Reminds contributors about docs
|
||||||
|
- Better project maintainability
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. **Related Issues Detection** 🔗
|
||||||
|
|
||||||
|
Automatically finds and links related open issues.
|
||||||
|
|
||||||
|
**How it works:**
|
||||||
|
|
||||||
|
- Extracts script names from changed files
|
||||||
|
- Searches open issues for matching names
|
||||||
|
- Links up to 5 most relevant issues
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 🔗 Related Issues
|
||||||
|
|
||||||
|
This PR may be related to the following open issues:
|
||||||
|
|
||||||
|
- #123: Docker script fails on Ubuntu 22.04
|
||||||
|
- #456: Add network configuration options
|
||||||
|
```
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
|
||||||
|
- Better context for reviewers
|
||||||
|
- Automatic cross-referencing
|
||||||
|
- Helps track issue resolution
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 7. **Validation Warnings** ⚠️
|
||||||
|
|
||||||
|
Provides helpful warnings when PR information is incomplete or inconsistent.
|
||||||
|
|
||||||
|
**Checks:**
|
||||||
|
|
||||||
|
- ✅ Change type checkbox is selected for script updates
|
||||||
|
- ✅ Website checkbox matches file changes
|
||||||
|
- ✅ Required labels are present
|
||||||
|
- ✅ Documentation updated for new features
|
||||||
|
|
||||||
|
**Example Warning:**
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## ⚠️ Validation Warnings
|
||||||
|
|
||||||
|
⚠️ **Missing change type**: Please check one of the change type checkboxes
|
||||||
|
(Bug fix, New feature, Refactoring, or Breaking change) in the PR description.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 8. **Changelog Preview** 📝
|
||||||
|
|
||||||
|
Shows contributors exactly how their PR will appear in the changelog.
|
||||||
|
|
||||||
|
**Example Preview:**
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 📝 Changelog Preview
|
||||||
|
|
||||||
|
This PR will appear in the changelog as:
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
- Fix docker script issue @username ([#123](url))
|
||||||
|
```
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
|
||||||
|
- Contributors see immediate feedback
|
||||||
|
- Reduces changelog errors
|
||||||
|
- Improves PR quality
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏷️ Label Priority System
|
||||||
|
|
||||||
|
When multiple change types are checked, only the highest priority label is applied:
|
||||||
|
|
||||||
|
1. 🐞 **Bugfix** (highest priority)
|
||||||
|
2. 🔧 **Refactor**
|
||||||
|
3. ✨ **Feature**
|
||||||
|
4. 💥 **Breaking Change** (lowest priority)
|
||||||
|
|
||||||
|
**Rationale:**
|
||||||
|
|
||||||
|
- Bug fixes are most important for users
|
||||||
|
- Prevents PRs from appearing in multiple subcategories
|
||||||
|
- Maintains clean changelog structure
|
||||||
|
|
||||||
|
**Note:** This applies to both template checkboxes AND conventional commit messages!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Changelog Categories
|
||||||
|
|
||||||
|
The bot automatically determines which changelog category your PR belongs to:
|
||||||
|
|
||||||
|
| Files Changed | Category | Note |
|
||||||
|
| ------------------------------------ | ------------------------------- | ------------------ |
|
||||||
|
| `ct/`, `vm/`, `install/`, `turnkey/` | 🚀 Updated Scripts | Standard scripts |
|
||||||
|
| `tools/` | 🛠️ Updated Tools | Utility tools |
|
||||||
|
| `misc/` | 🔧 Core Updates | Core functionality |
|
||||||
|
| `frontend/` (not JSON) | 🌐 Website | Frontend changes |
|
||||||
|
| `frontend/public/json/` | 🌐 Website > Script Information | Metadata updates |
|
||||||
|
| Documentation files | 🧰 Maintenance | Docs, README, etc. |
|
||||||
|
|
||||||
|
**Multi-Category PRs:**
|
||||||
|
PRs that change files in multiple categories will appear in each relevant category.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Bot Behavior
|
||||||
|
|
||||||
|
### When PR is Opened/Edited:
|
||||||
|
|
||||||
|
1. ✅ Analyzes changed files
|
||||||
|
2. ✅ Parses PR template checkboxes
|
||||||
|
3. ✅ Analyzes commit messages (conventional commits)
|
||||||
|
4. ✅ Calculates size label
|
||||||
|
5. ✅ Checks if first-time contributor
|
||||||
|
6. ✅ Applies appropriate labels
|
||||||
|
7. ✅ Removes conflicting labels
|
||||||
|
8. ✅ Checks for validation issues
|
||||||
|
9. ✅ Finds related issues
|
||||||
|
10. ✅ Posts/updates comment with all info
|
||||||
|
|
||||||
|
### Comment Structure:
|
||||||
|
|
||||||
|
A single bot comment contains (in order):
|
||||||
|
|
||||||
|
1. 🎉 Welcome message (if first-time contributor)
|
||||||
|
2. ⚠️ Validation warnings (if any)
|
||||||
|
3. 📝 Changelog preview (always)
|
||||||
|
4. 🔗 Related issues (if found)
|
||||||
|
5. ℹ️ Footer with PR size
|
||||||
|
|
||||||
|
### Comment Updates:
|
||||||
|
|
||||||
|
- Bot updates its own comment when PR is edited (no spam)
|
||||||
|
- Only posts new comment if none exists
|
||||||
|
- Welcome message is preserved across updates
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Complete Example
|
||||||
|
|
||||||
|
Here's what a first-time contributor might see:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 🎉 Welcome to the Community!
|
||||||
|
|
||||||
|
Thank you @newuser for your first contribution! 🙌
|
||||||
|
|
||||||
|
A maintainer will review your PR soon. Here are some helpful resources:
|
||||||
|
|
||||||
|
- Contributing Guide
|
||||||
|
- Code of Conduct
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ Validation Warnings
|
||||||
|
|
||||||
|
📚 **Documentation update recommended**: Consider updating documentation
|
||||||
|
for these code changes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Changelog Preview
|
||||||
|
|
||||||
|
This PR will appear in the changelog as:
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
- Add Docker network support @newuser ([#789](url))
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔗 Related Issues
|
||||||
|
|
||||||
|
This PR may be related to the following open issues:
|
||||||
|
|
||||||
|
- #456: Docker networking not working
|
||||||
|
- #123: Request: Custom network support
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_This is an automated message from the PR labeler bot. PR size: size: M_
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ For Maintainers
|
||||||
|
|
||||||
|
### Debugging Label Issues
|
||||||
|
|
||||||
|
If labels aren't being applied correctly:
|
||||||
|
|
||||||
|
1. Check PR template checkboxes are properly formatted
|
||||||
|
2. Verify commit messages use conventional format
|
||||||
|
3. Look for bot comment explaining label decisions
|
||||||
|
4. Check GitHub Actions logs for errors
|
||||||
|
5. Verify all required labels exist in repository
|
||||||
|
|
||||||
|
### Modifying Label Behavior
|
||||||
|
|
||||||
|
**Config files:**
|
||||||
|
|
||||||
|
- `.github/autolabeler-config.json` - File path → label mappings
|
||||||
|
- `.github/changelog-pr-config.json` - Changelog categories
|
||||||
|
- `.github/workflows/autolabeler.yml` - Core logic
|
||||||
|
|
||||||
|
**Priority order** can be changed in `autolabeler.yml`:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const priorityOrder = ["bugfix", "refactor", "feature", "breaking change"];
|
||||||
|
```
|
||||||
|
|
||||||
|
**Size thresholds** can be adjusted:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
if (totalChanges <= 10) labelsToAdd.add("size: XS");
|
||||||
|
else if (totalChanges <= 50) labelsToAdd.add("size: S");
|
||||||
|
// etc.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating Required Labels
|
||||||
|
|
||||||
|
Run these commands to create all size labels:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gh label create "size: XS" --description "1-10 lines" --color "00ff00"
|
||||||
|
gh label create "size: S" --description "11-50 lines" --color "7fff00"
|
||||||
|
gh label create "size: M" --description "51-200 lines" --color "ffff00"
|
||||||
|
gh label create "size: L" --description "201-500 lines" --color "ff8c00"
|
||||||
|
gh label create "size: XL" --description "500+ lines" --color "ff0000"
|
||||||
|
```
|
||||||
|
|
||||||
|
See [SETUP_NEW_LABELS.md](SETUP_NEW_LABELS.md) for full setup guide.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Testing Scenarios
|
||||||
|
|
||||||
|
### Test 1: Conventional Commits
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Commit with conventional format
|
||||||
|
git commit -m "feat: add new feature"
|
||||||
|
# Expected: feature label, even without checkbox
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test 2: Size Labels
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Small PR (< 50 lines)
|
||||||
|
# Expected: size: S label
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test 3: First-Time Contributor
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create PR from new contributor account
|
||||||
|
# Expected: Welcome message in bot comment
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test 4: Documentation Check
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Change .sh file, no .md changes
|
||||||
|
# Expected: Warning about missing docs
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test 5: Related Issues
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# PR changes "docker.sh"
|
||||||
|
# Expected: Links to issues mentioning "docker"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎉 Benefits Summary
|
||||||
|
|
||||||
|
✅ **Automation**: Less manual work for maintainers
|
||||||
|
✅ **Consistency**: All PRs follow same standard
|
||||||
|
✅ **Quality**: Multiple validation checks
|
||||||
|
✅ **Transparency**: Contributors see what happens
|
||||||
|
✅ **Community**: Better onboarding for new contributors
|
||||||
|
✅ **Context**: Automatic issue linking
|
||||||
|
✅ **Clean Changelogs**: Priority system prevents duplication
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐛 Troubleshooting
|
||||||
|
|
||||||
|
**Labels not applied?**
|
||||||
|
|
||||||
|
- Check if PR template checkboxes are properly formatted
|
||||||
|
- Try using conventional commit messages
|
||||||
|
- Ensure files changed match expected patterns
|
||||||
|
- Look for validation warnings in bot comment
|
||||||
|
|
||||||
|
**Size label missing?**
|
||||||
|
|
||||||
|
- Labels need to be created first (see setup guide)
|
||||||
|
- Check if label was removed manually
|
||||||
|
- Verify workflow has permissions to add labels
|
||||||
|
|
||||||
|
**Wrong category?**
|
||||||
|
|
||||||
|
- Verify file paths (tools/ vs ct/ vs misc/)
|
||||||
|
- Check if multiple categories apply (intended behavior)
|
||||||
|
- Review `.github/changelog-pr-config.json`
|
||||||
|
|
||||||
|
**Bot comment not appearing?**
|
||||||
|
|
||||||
|
- Check GitHub Actions logs
|
||||||
|
- Verify bot has comment permissions
|
||||||
|
- May take a few seconds after PR creation
|
||||||
|
- Check if PR is from a fork (requires pull_request_target)
|
||||||
|
|
||||||
|
**Related issues not found?**
|
||||||
|
|
||||||
|
- Script name must match issue title/body
|
||||||
|
- Only searches open issues
|
||||||
|
- Limited to top 5 results
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Questions?** Check the workflow logs or ask in the repository discussions.
|
||||||
7
.github/ISSUE_TEMPLATE/bug_report.yml
generated
vendored
7
.github/ISSUE_TEMPLATE/bug_report.yml
generated
vendored
@@ -13,7 +13,6 @@ body:
|
|||||||
|
|
||||||
Thank you for taking the time to report an issue! Please provide as much detail as possible to help us address the problem efficiently.
|
Thank you for taking the time to report an issue! Please provide as much detail as possible to help us address the problem efficiently.
|
||||||
|
|
||||||
|
|
||||||
- type: input
|
- type: input
|
||||||
id: guidelines
|
id: guidelines
|
||||||
attributes:
|
attributes:
|
||||||
@@ -34,8 +33,7 @@ body:
|
|||||||
id: script_command
|
id: script_command
|
||||||
attributes:
|
attributes:
|
||||||
label: 📂 What was the exact command used to execute the script?
|
label: 📂 What was the exact command used to execute the script?
|
||||||
placeholder: "e.g., bash -c \"$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/zigbee2mqtt.sh)\" or \"update\""
|
placeholder: 'e.g., bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/zigbee2mqtt.sh)" or "update"'
|
||||||
validations:
|
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
@@ -63,7 +61,8 @@ body:
|
|||||||
- Debian 13
|
- Debian 13
|
||||||
- Ubuntu 22.04
|
- Ubuntu 22.04
|
||||||
- Ubuntu 24.04
|
- Ubuntu 24.04
|
||||||
- Ubuntu 24.10
|
- Ubuntu 25.04
|
||||||
|
- Other
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
|
|||||||
79
.github/SETUP_NEW_LABELS.md
generated
vendored
Normal file
79
.github/SETUP_NEW_LABELS.md
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
# 🏷️ Setup New Labels
|
||||||
|
|
||||||
|
The autolabeler now uses additional size labels. These need to be created in your repository.
|
||||||
|
|
||||||
|
## Required Labels
|
||||||
|
|
||||||
|
### Size Labels (New)
|
||||||
|
|
||||||
|
These labels are automatically added based on the number of lines changed:
|
||||||
|
|
||||||
|
| Label | Lines Changed | Color | Description |
|
||||||
|
| ---------- | ------------- | --------- | ----------------------------- |
|
||||||
|
| `size: XS` | 1-10 | `#00ff00` | Extra Small - Minimal changes |
|
||||||
|
| `size: S` | 11-50 | `#7fff00` | Small - Minor changes |
|
||||||
|
| `size: M` | 51-200 | `#ffff00` | Medium - Moderate changes |
|
||||||
|
| `size: L` | 201-500 | `#ff8c00` | Large - Significant changes |
|
||||||
|
| `size: XL` | 500+ | `#ff0000` | Extra Large - Major changes |
|
||||||
|
|
||||||
|
## Quick Setup Commands
|
||||||
|
|
||||||
|
Run these commands in your terminal to create all labels at once:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create size labels
|
||||||
|
gh label create "size: XS" --description "Extra Small - 1-10 lines changed" --color "00ff00"
|
||||||
|
gh label create "size: S" --description "Small - 11-50 lines changed" --color "7fff00"
|
||||||
|
gh label create "size: M" --description "Medium - 51-200 lines changed" --color "ffff00"
|
||||||
|
gh label create "size: L" --description "Large - 201-500 lines changed" --color "ff8c00"
|
||||||
|
gh label create "size: XL" --description "Extra Large - 500+ lines changed" --color "ff0000"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Manual Setup (GitHub UI)
|
||||||
|
|
||||||
|
1. Go to: `https://github.com/community-scripts/ProxmoxVE/labels`
|
||||||
|
2. Click "New label" for each label
|
||||||
|
3. Fill in:
|
||||||
|
- **Name**: Use exact names from table above
|
||||||
|
- **Description**: Copy from table
|
||||||
|
- **Color**: Use hex codes from table (without #)
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
After creating labels, test by:
|
||||||
|
|
||||||
|
1. Creating a small PR (< 10 lines) → should get `size: XS`
|
||||||
|
2. Check that bot comment includes size in footer
|
||||||
|
|
||||||
|
## Optional: Label Sync
|
||||||
|
|
||||||
|
For automated label management, consider using [github-label-sync](https://github.com/Financial-Times/github-label-sync):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"size: XS": {
|
||||||
|
"color": "00ff00",
|
||||||
|
"description": "Extra Small - 1-10 lines changed"
|
||||||
|
},
|
||||||
|
"size: S": {
|
||||||
|
"color": "7fff00",
|
||||||
|
"description": "Small - 11-50 lines changed"
|
||||||
|
},
|
||||||
|
"size: M": {
|
||||||
|
"color": "ffff00",
|
||||||
|
"description": "Medium - 51-200 lines changed"
|
||||||
|
},
|
||||||
|
"size: L": {
|
||||||
|
"color": "ff8c00",
|
||||||
|
"description": "Large - 201-500 lines changed"
|
||||||
|
},
|
||||||
|
"size: XL": {
|
||||||
|
"color": "ff0000",
|
||||||
|
"description": "Extra Large - 500+ lines changed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Note**: The autolabeler will work even if labels don't exist yet, but they won't be visible on PRs until created.
|
||||||
13
.github/autolabeler-config.json
generated
vendored
13
.github/autolabeler-config.json
generated
vendored
@@ -101,20 +101,11 @@
|
|||||||
"excludeGlobs": []
|
"excludeGlobs": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"addon": [
|
"tools": [
|
||||||
{
|
{
|
||||||
"fileStatus": null,
|
"fileStatus": null,
|
||||||
"includeGlobs": [
|
"includeGlobs": [
|
||||||
"tools/addon/**"
|
"tools/**"
|
||||||
],
|
|
||||||
"excludeGlobs": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"pve-tool": [
|
|
||||||
{
|
|
||||||
"fileStatus": null,
|
|
||||||
"includeGlobs": [
|
|
||||||
"tools/pve/**"
|
|
||||||
],
|
],
|
||||||
"excludeGlobs": []
|
"excludeGlobs": []
|
||||||
}
|
}
|
||||||
|
|||||||
175
.github/changelog-pr-config.json
generated
vendored
175
.github/changelog-pr-config.json
generated
vendored
@@ -10,6 +10,10 @@
|
|||||||
"labels": [
|
"labels": [
|
||||||
"update script"
|
"update script"
|
||||||
],
|
],
|
||||||
|
"excludeLabels": [
|
||||||
|
"tools",
|
||||||
|
"core"
|
||||||
|
],
|
||||||
"subCategories": [
|
"subCategories": [
|
||||||
{
|
{
|
||||||
"title": "🐞 Bug Fixes",
|
"title": "🐞 Bug Fixes",
|
||||||
@@ -18,6 +22,13 @@
|
|||||||
],
|
],
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": "🔧 Refactor",
|
||||||
|
"labels": [
|
||||||
|
"refactor"
|
||||||
|
],
|
||||||
|
"notes": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"title": "✨ New Features",
|
"title": "✨ New Features",
|
||||||
"labels": [
|
"labels": [
|
||||||
@@ -31,6 +42,61 @@
|
|||||||
"breaking change"
|
"breaking change"
|
||||||
],
|
],
|
||||||
"notes": []
|
"notes": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "🛠️ Updated Tools",
|
||||||
|
"labels": [
|
||||||
|
"update script",
|
||||||
|
"tools"
|
||||||
|
],
|
||||||
|
"requireAllLabels": true,
|
||||||
|
"subCategories": [
|
||||||
|
{
|
||||||
|
"title": "<22> Bug Fixes",
|
||||||
|
"labels": [
|
||||||
|
"bugfix"
|
||||||
|
],
|
||||||
|
"notes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "<22>🔧 Refactor",
|
||||||
|
"labels": [
|
||||||
|
"refactor"
|
||||||
|
],
|
||||||
|
"notes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "✨ New Features",
|
||||||
|
"labels": [
|
||||||
|
"feature"
|
||||||
|
],
|
||||||
|
"notes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "💥 Breaking Changes",
|
||||||
|
"labels": [
|
||||||
|
"breaking change"
|
||||||
|
],
|
||||||
|
"notes": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "🔧 Core Updates",
|
||||||
|
"labels": [
|
||||||
|
"update script",
|
||||||
|
"core"
|
||||||
|
],
|
||||||
|
"requireAllLabels": true,
|
||||||
|
"subCategories": [
|
||||||
|
{
|
||||||
|
"title": "🐞 Bug Fixes",
|
||||||
|
"labels": [
|
||||||
|
"bugfix"
|
||||||
|
],
|
||||||
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "🔧 Refactor",
|
"title": "🔧 Refactor",
|
||||||
@@ -38,6 +104,63 @@
|
|||||||
"refactor"
|
"refactor"
|
||||||
],
|
],
|
||||||
"notes": []
|
"notes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "✨ New Features",
|
||||||
|
"labels": [
|
||||||
|
"feature"
|
||||||
|
],
|
||||||
|
"notes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "💥 Breaking Changes",
|
||||||
|
"labels": [
|
||||||
|
"breaking change"
|
||||||
|
],
|
||||||
|
"notes": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "🌐 Website",
|
||||||
|
"labels": [
|
||||||
|
"website"
|
||||||
|
],
|
||||||
|
"subCategories": [
|
||||||
|
{
|
||||||
|
"title": "<22> Bug Fixes",
|
||||||
|
"labels": [
|
||||||
|
"bugfix"
|
||||||
|
],
|
||||||
|
"notes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "<22> Refactor",
|
||||||
|
"labels": [
|
||||||
|
"refactor"
|
||||||
|
],
|
||||||
|
"notes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "✨ New Features",
|
||||||
|
"labels": [
|
||||||
|
"feature"
|
||||||
|
],
|
||||||
|
"notes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "<22> Breaking Changes",
|
||||||
|
"labels": [
|
||||||
|
"breaking change"
|
||||||
|
],
|
||||||
|
"notes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "<22> Script Information",
|
||||||
|
"labels": [
|
||||||
|
"json"
|
||||||
|
],
|
||||||
|
"notes": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -54,6 +177,13 @@
|
|||||||
],
|
],
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": "🔧 Refactor",
|
||||||
|
"labels": [
|
||||||
|
"refactor"
|
||||||
|
],
|
||||||
|
"notes": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"title": "✨ New Features",
|
"title": "✨ New Features",
|
||||||
"labels": [
|
"labels": [
|
||||||
@@ -69,7 +199,7 @@
|
|||||||
"notes": []
|
"notes": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "📡 API",
|
"title": "<EFBFBD> API",
|
||||||
"labels": [
|
"labels": [
|
||||||
"api"
|
"api"
|
||||||
],
|
],
|
||||||
@@ -95,49 +225,6 @@
|
|||||||
"maintenance"
|
"maintenance"
|
||||||
],
|
],
|
||||||
"notes": []
|
"notes": []
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "🔧 Refactor",
|
|
||||||
"labels": [
|
|
||||||
"refactor"
|
|
||||||
],
|
|
||||||
"notes": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "🌐 Website",
|
|
||||||
"labels": [
|
|
||||||
"website"
|
|
||||||
],
|
|
||||||
"subCategories": [
|
|
||||||
{
|
|
||||||
"title": "🐞 Bug Fixes",
|
|
||||||
"labels": [
|
|
||||||
"bugfix"
|
|
||||||
],
|
|
||||||
"notes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "✨ New Features",
|
|
||||||
"labels": [
|
|
||||||
"feature"
|
|
||||||
],
|
|
||||||
"notes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "💥 Breaking Changes",
|
|
||||||
"labels": [
|
|
||||||
"breaking change"
|
|
||||||
],
|
|
||||||
"notes": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "📝 Script Information",
|
|
||||||
"labels": [
|
|
||||||
"json"
|
|
||||||
],
|
|
||||||
"notes": []
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
308
.github/workflows/autolabeler.yml
generated
vendored
308
.github/workflows/autolabeler.yml
generated
vendored
@@ -35,6 +35,7 @@ jobs:
|
|||||||
|
|
||||||
const prNumber = context.payload.pull_request.number;
|
const prNumber = context.payload.pull_request.number;
|
||||||
const prBody = context.payload.pull_request.body || "";
|
const prBody = context.payload.pull_request.body || "";
|
||||||
|
const prAuthor = context.payload.pull_request.user.login;
|
||||||
|
|
||||||
let labelsToAdd = new Set();
|
let labelsToAdd = new Set();
|
||||||
|
|
||||||
@@ -45,6 +46,24 @@ jobs:
|
|||||||
});
|
});
|
||||||
const prFiles = prListFilesResponse.data;
|
const prFiles = prListFilesResponse.data;
|
||||||
|
|
||||||
|
// Get commits for commit message analysis
|
||||||
|
const { data: commits } = await github.rest.pulls.listCommits({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
pull_number: prNumber,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if this is a first-time contributor
|
||||||
|
const { data: prsByAuthor } = await github.rest.pulls.list({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
state: 'all',
|
||||||
|
per_page: 5
|
||||||
|
});
|
||||||
|
const isFirstTimeContributor = !prsByAuthor.some(pr =>
|
||||||
|
pr.user.login === prAuthor && pr.number !== prNumber && pr.merged_at
|
||||||
|
);
|
||||||
|
|
||||||
for (const [label, rules] of Object.entries(autolabelerConfig)) {
|
for (const [label, rules] of Object.entries(autolabelerConfig)) {
|
||||||
const shouldAddLabel = prFiles.some((prFile) => {
|
const shouldAddLabel = prFiles.some((prFile) => {
|
||||||
return rules.some((rule) => {
|
return rules.some((rule) => {
|
||||||
@@ -57,28 +76,48 @@ jobs:
|
|||||||
|
|
||||||
if (shouldAddLabel) {
|
if (shouldAddLabel) {
|
||||||
labelsToAdd.add(label);
|
labelsToAdd.add(label);
|
||||||
if (label === "update script") {
|
if (label === "update script" || label === "new script") {
|
||||||
for (const prFile of prFiles) {
|
for (const prFile of prFiles) {
|
||||||
const filename = prFile.filename;
|
const filename = prFile.filename;
|
||||||
if (filename.startsWith("vm/")) labelsToAdd.add("vm");
|
if (filename.startsWith("vm/")) labelsToAdd.add("vm");
|
||||||
if (filename.startsWith("tools/addon/")) labelsToAdd.add("addon");
|
if (filename.startsWith("tools/")) labelsToAdd.add("tools");
|
||||||
if (filename.startsWith("tools/pve/")) labelsToAdd.add("pve-tool");
|
if (filename.startsWith("misc/")) labelsToAdd.add("core");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (labelsToAdd.size < 2) {
|
// Feature 2: Analyze commit messages for conventional commits
|
||||||
|
const commitMessages = commits.map(c => c.commit.message).join('\n');
|
||||||
|
const conventionalCommitLabels = [];
|
||||||
|
|
||||||
|
if (/^fix(\(.*?\))?:/im.test(commitMessages)) {
|
||||||
|
conventionalCommitLabels.push("bugfix");
|
||||||
|
}
|
||||||
|
if (/^feat(\(.*?\))?:/im.test(commitMessages)) {
|
||||||
|
conventionalCommitLabels.push("feature");
|
||||||
|
}
|
||||||
|
if (/^refactor(\(.*?\))?:/im.test(commitMessages)) {
|
||||||
|
conventionalCommitLabels.push("refactor");
|
||||||
|
}
|
||||||
|
if (/BREAKING[:\s]CHANGE/i.test(commitMessages) || /^[a-z]+(\(.*?\))?!:/im.test(commitMessages)) {
|
||||||
|
conventionalCommitLabels.push("breaking change");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse PR template for content type labels (bugfix, feature, refactor, breaking change)
|
||||||
const templateLabelMappings = {
|
const templateLabelMappings = {
|
||||||
"🐞 **Bug fix**": "bugfix",
|
"🐞 **Bug fix**": "bugfix",
|
||||||
"✨ **New feature**": "feature",
|
"✨ **New feature**": "feature",
|
||||||
"💥 **Breaking change**": "breaking change",
|
"💥 **Breaking change**": "breaking change",
|
||||||
"🆕 **New script**": "new script",
|
"🆕 **New script**": "new script",
|
||||||
"🌍 **Website update**": "website", // handled special
|
"🌍 **Website update**": "website",
|
||||||
"🔧 **Refactoring / Code Cleanup**": "refactor",
|
"🔧 **Refactoring / Code Cleanup**": "refactor",
|
||||||
"📝 **Documentation update**": "documentation" // mapped to maintenance
|
"📝 **Documentation update**": "documentation"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const contentLabels = ["bugfix", "feature", "refactor", "breaking change"];
|
||||||
|
const checkedContentLabels = [];
|
||||||
|
|
||||||
for (const [checkbox, label] of Object.entries(templateLabelMappings)) {
|
for (const [checkbox, label] of Object.entries(templateLabelMappings)) {
|
||||||
const escapedCheckbox = checkbox.replace(/([.*+?^=!:${}()|[\]\/\\])/g, "\\$1");
|
const escapedCheckbox = checkbox.replace(/([.*+?^=!:${}()|[\]\/\\])/g, "\\$1");
|
||||||
const regex = new RegExp(`- \\[(x|X)\\]\\s*${escapedCheckbox}`, "i");
|
const regex = new RegExp(`- \\[(x|X)\\]\\s*${escapedCheckbox}`, "i");
|
||||||
@@ -86,20 +125,267 @@ jobs:
|
|||||||
if (regex.test(prBody)) {
|
if (regex.test(prBody)) {
|
||||||
if (label === "website") {
|
if (label === "website") {
|
||||||
const hasJson = prFiles.some((f) => f.filename.startsWith("frontend/public/json/"));
|
const hasJson = prFiles.some((f) => f.filename.startsWith("frontend/public/json/"));
|
||||||
const hasUpdateScript = labelsToAdd.has("update script");
|
|
||||||
const hasContentLabel = ["bugfix", "feature", "refactor"].some((l) => labelsToAdd.has(l));
|
|
||||||
|
|
||||||
if (!(hasUpdateScript && hasContentLabel)) {
|
|
||||||
labelsToAdd.add(hasJson ? "json" : "website");
|
labelsToAdd.add(hasJson ? "json" : "website");
|
||||||
}
|
|
||||||
} else if (label === "documentation") {
|
} else if (label === "documentation") {
|
||||||
labelsToAdd.add("maintenance");
|
labelsToAdd.add("maintenance");
|
||||||
|
} else if (label === "new script") {
|
||||||
|
labelsToAdd.add("new script");
|
||||||
|
} else if (contentLabels.includes(label)) {
|
||||||
|
checkedContentLabels.push(label);
|
||||||
} else {
|
} else {
|
||||||
labelsToAdd.add(label);
|
labelsToAdd.add(label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Priority system: Combine template checkboxes and conventional commits
|
||||||
|
// Merge both sources
|
||||||
|
const allCheckedLabels = [...new Set([...checkedContentLabels, ...conventionalCommitLabels])];
|
||||||
|
|
||||||
|
// Priority: bugfix > refactor > feature > breaking change
|
||||||
|
if (allCheckedLabels.length > 0) {
|
||||||
|
const priorityOrder = ["bugfix", "refactor", "feature", "breaking change"];
|
||||||
|
const highestPriorityLabel = priorityOrder.find(label => allCheckedLabels.includes(label));
|
||||||
|
if (highestPriorityLabel) {
|
||||||
|
labelsToAdd.add(highestPriorityLabel);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feature 3: Add size labels based on changes
|
||||||
|
const totalChanges = prFiles.reduce((sum, file) => sum + file.additions + file.deletions, 0);
|
||||||
|
if (totalChanges <= 10) {
|
||||||
|
labelsToAdd.add("size: XS");
|
||||||
|
} else if (totalChanges <= 50) {
|
||||||
|
labelsToAdd.add("size: S");
|
||||||
|
} else if (totalChanges <= 200) {
|
||||||
|
labelsToAdd.add("size: M");
|
||||||
|
} else if (totalChanges <= 500) {
|
||||||
|
labelsToAdd.add("size: L");
|
||||||
|
} else {
|
||||||
|
labelsToAdd.add("size: XL");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get current PR labels
|
||||||
|
const { data: currentPR } = await github.rest.pulls.get({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
pull_number: prNumber,
|
||||||
|
});
|
||||||
|
const currentLabels = currentPR.labels.map(label => label.name.toLowerCase());
|
||||||
|
|
||||||
|
// Label Cleanup: Remove outdated content labels and size labels
|
||||||
|
const allContentLabels = ["bugfix", "feature", "refactor", "breaking change"];
|
||||||
|
const allSizeLabels = ["size: XS", "size: S", "size: M", "size: L", "size: XL"];
|
||||||
|
const labelsToRemove = [
|
||||||
|
...allContentLabels.filter(label => currentLabels.includes(label) && !labelsToAdd.has(label)),
|
||||||
|
...allSizeLabels.filter(label => currentLabels.includes(label.toLowerCase()) && !labelsToAdd.has(label))
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const label of labelsToRemove) {
|
||||||
|
try {
|
||||||
|
await github.rest.issues.removeLabel({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: prNumber,
|
||||||
|
name: label,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
// Label might not exist, ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation: Check for missing information
|
||||||
|
const warnings = [];
|
||||||
|
const hasUpdateOrNewScript = labelsToAdd.has("update script") || labelsToAdd.has("new script");
|
||||||
|
const hasContentLabel = allContentLabels.some(label => labelsToAdd.has(label));
|
||||||
|
|
||||||
|
if (hasUpdateOrNewScript && !hasContentLabel && !labelsToAdd.has("new script")) {
|
||||||
|
warnings.push("⚠️ **Missing change type**: Please check one of the change type checkboxes (Bug fix, New feature, Refactoring, or Breaking change) in the PR description.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labelsToAdd.has("website") && !labelsToAdd.has("json") && prFiles.some(f => f.filename.includes("frontend/"))) {
|
||||||
|
const hasCheckbox = /- \[(x|X)\]\s*🌍 \*\*Website update\*\*/i.test(prBody);
|
||||||
|
if (!hasCheckbox) {
|
||||||
|
warnings.push("⚠️ **Missing checkbox**: Please check the '🌍 Website update' checkbox in the PR description.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feature 5: Documentation check
|
||||||
|
const codeFiles = prFiles.filter(f => /\.(sh|func|go|js|ts|tsx|jsx)$/.test(f.filename));
|
||||||
|
const docFiles = prFiles.filter(f => /\.(md|txt)$/i.test(f.filename) || f.filename.includes('README'));
|
||||||
|
|
||||||
|
if (codeFiles.length > 0 && docFiles.length === 0 && !labelsToAdd.has("refactor") && !labelsToAdd.has("bugfix")) {
|
||||||
|
warnings.push("📚 **Documentation update recommended**: Consider updating documentation for these code changes.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feature 6: Related issues detection
|
||||||
|
let relatedIssuesText = "";
|
||||||
|
const scriptFiles = prFiles.filter(f => /\.(sh|func)$/.test(f.filename));
|
||||||
|
if (scriptFiles.length > 0) {
|
||||||
|
const scriptNames = scriptFiles.map(f => {
|
||||||
|
const match = f.filename.match(/([^\/]+)\.(sh|func)$/);
|
||||||
|
return match ? match[1] : null;
|
||||||
|
}).filter(Boolean);
|
||||||
|
|
||||||
|
if (scriptNames.length > 0) {
|
||||||
|
try {
|
||||||
|
const { data: openIssues } = await github.rest.issues.listForRepo({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
state: 'open',
|
||||||
|
per_page: 100
|
||||||
|
});
|
||||||
|
|
||||||
|
const related = [];
|
||||||
|
for (const scriptName of scriptNames) {
|
||||||
|
const matchingIssues = openIssues.filter(issue =>
|
||||||
|
!issue.pull_request &&
|
||||||
|
(issue.title.toLowerCase().includes(scriptName.toLowerCase()) ||
|
||||||
|
(issue.body || '').toLowerCase().includes(scriptName.toLowerCase()))
|
||||||
|
);
|
||||||
|
related.push(...matchingIssues);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uniqueRelated = [...new Map(related.map(i => [i.number, i])).values()];
|
||||||
|
if (uniqueRelated.length > 0) {
|
||||||
|
relatedIssuesText = "\n\n## 🔗 Related Issues\n\n";
|
||||||
|
relatedIssuesText += "This PR may be related to the following open issues:\n";
|
||||||
|
uniqueRelated.slice(0, 5).forEach(issue => {
|
||||||
|
relatedIssuesText += `- #${issue.number}: ${issue.title}\n`;
|
||||||
|
});
|
||||||
|
if (uniqueRelated.length > 5) {
|
||||||
|
relatedIssuesText += `- _...and ${uniqueRelated.length - 5} more_\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching related issues:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate Changelog Preview
|
||||||
|
let changelogPreview = "## 📝 Changelog Preview\n\n";
|
||||||
|
changelogPreview += "This PR will appear in the changelog as:\n\n";
|
||||||
|
|
||||||
|
const categories = [];
|
||||||
|
|
||||||
|
if (labelsToAdd.has("new script")) {
|
||||||
|
changelogPreview += "### 🆕 New Scripts\n";
|
||||||
|
changelogPreview += `- ${currentPR.title} @${currentPR.user.login} ([#${prNumber}](${currentPR.html_url}))\n\n`;
|
||||||
|
} else {
|
||||||
|
if (labelsToAdd.has("update script")) {
|
||||||
|
if (labelsToAdd.has("tools")) {
|
||||||
|
categories.push({ name: "🛠️ Updated Tools", label: labelsToAdd });
|
||||||
|
} else if (labelsToAdd.has("core")) {
|
||||||
|
categories.push({ name: "🔧 Core Updates", label: labelsToAdd });
|
||||||
|
} else {
|
||||||
|
categories.push({ name: "🚀 Updated Scripts", label: labelsToAdd });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labelsToAdd.has("website") || labelsToAdd.has("json")) {
|
||||||
|
categories.push({ name: "🌐 Website", label: labelsToAdd });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labelsToAdd.has("maintenance")) {
|
||||||
|
categories.push({ name: "🧰 Maintenance", label: labelsToAdd });
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const category of categories) {
|
||||||
|
changelogPreview += `### ${category.name}\n`;
|
||||||
|
|
||||||
|
const subCategoryMap = {
|
||||||
|
"bugfix": " - #### 🐞 Bug Fixes",
|
||||||
|
"refactor": " - #### 🔧 Refactor",
|
||||||
|
"feature": " - #### ✨ New Features",
|
||||||
|
"breaking change": " - #### 💥 Breaking Changes"
|
||||||
|
};
|
||||||
|
|
||||||
|
const matchedSubCat = allContentLabels.find(label => labelsToAdd.has(label));
|
||||||
|
if (matchedSubCat && subCategoryMap[matchedSubCat]) {
|
||||||
|
changelogPreview += `${subCategoryMap[matchedSubCat]}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labelsToAdd.has("json")) {
|
||||||
|
changelogPreview += " - #### 📝 Script Information\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
changelogPreview += ` - ${currentPR.title} @${currentPR.user.login} ([#${prNumber}](${currentPR.html_url}))\n\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (categories.length === 0) {
|
||||||
|
changelogPreview += "_This PR may not appear in the changelog. Please ensure proper labels are set._\n\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post comment with warnings and changelog preview
|
||||||
|
if (warnings.length > 0 || changelogPreview || relatedIssuesText || isFirstTimeContributor) {
|
||||||
|
let commentBody = "";
|
||||||
|
|
||||||
|
// Feature 4: First-time contributor welcome
|
||||||
|
if (isFirstTimeContributor) {
|
||||||
|
commentBody += "## 🎉 Welcome to the Community!\n\n";
|
||||||
|
commentBody += `Thank you **@${prAuthor}** for your first contribution! 🙌\n\n`;
|
||||||
|
commentBody += "A maintainer will review your PR soon. Here are some helpful resources:\n";
|
||||||
|
commentBody += "- [Contributing Guide](https://github.com/community-scripts/ProxmoxVE/blob/main/.github/CONTRIBUTOR_AND_GUIDES/CONTRIBUTING.md)\n";
|
||||||
|
commentBody += "- [Code of Conduct](https://github.com/community-scripts/ProxmoxVE/blob/main/.github/CODE_OF_CONDUCT.md)\n\n";
|
||||||
|
commentBody += "---\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (warnings.length > 0) {
|
||||||
|
commentBody += "## ⚠️ Validation Warnings\n\n";
|
||||||
|
commentBody += warnings.join("\n\n") + "\n\n---\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
commentBody += changelogPreview;
|
||||||
|
|
||||||
|
if (relatedIssuesText) {
|
||||||
|
commentBody += relatedIssuesText;
|
||||||
|
}
|
||||||
|
|
||||||
|
commentBody += "\n\n---\n";
|
||||||
|
commentBody += `_This is an automated message from the PR labeler bot. PR size: ${Array.from(labelsToAdd).find(l => l.startsWith('size:')) || 'unknown'}_`;
|
||||||
|
|
||||||
|
// Check if we already posted a comment
|
||||||
|
const { data: comments } = await github.rest.issues.listComments({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: prNumber,
|
||||||
|
});
|
||||||
|
|
||||||
|
const botComment = comments.find(comment =>
|
||||||
|
comment.user.login === "github-actions[bot]" &&
|
||||||
|
(comment.body.includes("Changelog Preview") || comment.body.includes("Welcome to the Community"))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (botComment) {
|
||||||
|
// Update existing comment (but keep welcome message if it was there)
|
||||||
|
let updatedBody = commentBody;
|
||||||
|
if (botComment.body.includes("Welcome to the Community") && !isFirstTimeContributor) {
|
||||||
|
// Preserve welcome message from original comment
|
||||||
|
const welcomeSection = botComment.body.match(/## 🎉 Welcome to the Community![\s\S]*?---\n\n/);
|
||||||
|
if (welcomeSection) {
|
||||||
|
updatedBody = welcomeSection[0] + commentBody;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await github.rest.issues.updateComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
comment_id: botComment.id,
|
||||||
|
body: updatedBody,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Create new comment
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: prNumber,
|
||||||
|
body: commentBody,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (labelsToAdd.size === 0) {
|
if (labelsToAdd.size === 0) {
|
||||||
labelsToAdd.add("needs triage");
|
labelsToAdd.add("needs triage");
|
||||||
}
|
}
|
||||||
|
|||||||
88
.github/workflows/changelog-pr.yml
generated
vendored
88
.github/workflows/changelog-pr.yml
generated
vendored
@@ -67,29 +67,12 @@ jobs:
|
|||||||
const categorizedPRs = changelogConfig.map(obj => ({
|
const categorizedPRs = changelogConfig.map(obj => ({
|
||||||
...obj,
|
...obj,
|
||||||
notes: [],
|
notes: [],
|
||||||
subCategories: obj.subCategories ?? (
|
requireAllLabels: obj.requireAllLabels ?? false,
|
||||||
obj.labels.includes("update script") ? [
|
excludeLabels: obj.excludeLabels ?? [],
|
||||||
{ title: "🐞 Bug Fixes", labels: ["bugfix"], notes: [] },
|
subCategories: obj.subCategories ? obj.subCategories.map(sub => ({
|
||||||
{ title: "✨ New Features", labels: ["feature"], notes: [] },
|
...sub,
|
||||||
{ title: "💥 Breaking Changes", labels: ["breaking change"], notes: [] },
|
notes: []
|
||||||
{ title: "🔧 Refactor", labels: ["refactor"], notes: [] },
|
})) : []
|
||||||
] :
|
|
||||||
obj.labels.includes("maintenance") ? [
|
|
||||||
{ title: "🐞 Bug Fixes", labels: ["bugfix"], notes: [] },
|
|
||||||
{ title: "✨ New Features", labels: ["feature"], notes: [] },
|
|
||||||
{ title: "💥 Breaking Changes", labels: ["breaking change"], notes: [] },
|
|
||||||
{ title: "📡 API", labels: ["api"], notes: [] },
|
|
||||||
{ title: "Github", labels: ["github"], notes: [] },
|
|
||||||
{ title: "📝 Documentation", labels: ["maintenance"], notes: [] },
|
|
||||||
{ title: "🔧 Refactor", labels: ["refactor"], notes: [] }
|
|
||||||
] :
|
|
||||||
obj.labels.includes("website") ? [
|
|
||||||
{ title: "🐞 Bug Fixes", labels: ["bugfix"], notes: [] },
|
|
||||||
{ title: "✨ New Features", labels: ["feature"], notes: [] },
|
|
||||||
{ title: "💥 Breaking Changes", labels: ["breaking change"], notes: [] },
|
|
||||||
{ title: "Script Information", labels: ["json"], notes: [] }
|
|
||||||
] : []
|
|
||||||
)
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const latestDateInChangelog = new Date(process.env.LATEST_DATE);
|
const latestDateInChangelog = new Date(process.env.LATEST_DATE);
|
||||||
@@ -115,8 +98,9 @@ jobs:
|
|||||||
|
|
||||||
for (const pr of filteredPRs) {
|
for (const pr of filteredPRs) {
|
||||||
const prLabels = pr.labels.map(label => label.name.toLowerCase());
|
const prLabels = pr.labels.map(label => label.name.toLowerCase());
|
||||||
if (pr.user.login.includes("push-app-to-main[bot]")) {
|
let prNote;
|
||||||
|
|
||||||
|
if (pr.user.login.includes("push-app-to-main[bot]")) {
|
||||||
const scriptName = pr.title;
|
const scriptName = pr.title;
|
||||||
try {
|
try {
|
||||||
const { data: relatedIssues } = await github.rest.issues.listForRepo({
|
const { data: relatedIssues } = await github.rest.issues.listForRepo({
|
||||||
@@ -132,34 +116,57 @@ jobs:
|
|||||||
|
|
||||||
if (matchingIssue) {
|
if (matchingIssue) {
|
||||||
const issueAuthor = matchingIssue.user.login;
|
const issueAuthor = matchingIssue.user.login;
|
||||||
const issueAuthorUrl = `https://github.com/${issueAuthor}`;
|
prNote = `- ${pr.title} @${issueAuthor} ([#${pr.number}](${pr.html_url}))`;
|
||||||
prNote = `- ${pr.title} [@${issueAuthor}](${issueAuthorUrl}) ([#${pr.number}](${pr.html_url}))`;
|
} else {
|
||||||
}
|
|
||||||
else {
|
|
||||||
prNote = `- ${pr.title} ([#${pr.number}](${pr.html_url}))`;
|
prNote = `- ${pr.title} ([#${pr.number}](${pr.html_url}))`;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error fetching related issues: ${error}`);
|
console.error(`Error fetching related issues: ${error}`);
|
||||||
prNote = `- ${pr.title} ([#${pr.number}](${pr.html_url}))`;
|
prNote = `- ${pr.title} ([#${pr.number}](${pr.html_url}))`;
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
prNote = `- ${pr.title} [@${pr.user.login}](https://github.com/${pr.user.login}) ([#${pr.number}](${pr.html_url}))`;
|
prNote = `- ${pr.title} @${pr.user.login} ([#${pr.number}](${pr.html_url}))`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle "new script" separately - always goes to New Scripts category
|
||||||
if (prLabels.includes("new script")) {
|
if (prLabels.includes("new script")) {
|
||||||
const newScriptCategory = categorizedPRs.find(category =>
|
const newScriptCategory = categorizedPRs.find(category =>
|
||||||
category.title === "New Scripts" || category.labels.includes("new script"));
|
category.title === "🆕 New Scripts" || category.labels.includes("new script")
|
||||||
|
);
|
||||||
if (newScriptCategory) {
|
if (newScriptCategory) {
|
||||||
newScriptCategory.notes.push(prNote);
|
newScriptCategory.notes.push(prNote);
|
||||||
}
|
}
|
||||||
} else {
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let categorized = false;
|
// For other PRs, check all applicable categories (can appear in multiple)
|
||||||
const priorityCategories = categorizedPRs.slice();
|
for (const category of categorizedPRs) {
|
||||||
for (const category of priorityCategories) {
|
// Skip "new script" and unlabelled categories
|
||||||
if (categorized) break;
|
if (category.labels.includes("new script") || category.labels.length === 0) {
|
||||||
if (category.labels.some(label => prLabels.includes(label))) {
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if PR matches category requirements
|
||||||
|
let matchesCategory = false;
|
||||||
|
|
||||||
|
if (category.requireAllLabels) {
|
||||||
|
// All labels must be present
|
||||||
|
matchesCategory = category.labels.every(label => prLabels.includes(label));
|
||||||
|
} else {
|
||||||
|
// At least one label must be present
|
||||||
|
matchesCategory = category.labels.some(label => prLabels.includes(label));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check exclude labels
|
||||||
|
if (matchesCategory && category.excludeLabels.length > 0) {
|
||||||
|
const hasExcludedLabel = category.excludeLabels.some(label => prLabels.includes(label));
|
||||||
|
if (hasExcludedLabel) {
|
||||||
|
matchesCategory = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchesCategory) {
|
||||||
|
// Try to find matching subcategory
|
||||||
if (category.subCategories && category.subCategories.length > 0) {
|
if (category.subCategories && category.subCategories.length > 0) {
|
||||||
const subCategory = category.subCategories.find(sub =>
|
const subCategory = category.subCategories.find(sub =>
|
||||||
sub.labels.some(label => prLabels.includes(label))
|
sub.labels.some(label => prLabels.includes(label))
|
||||||
@@ -168,18 +175,17 @@ jobs:
|
|||||||
if (subCategory) {
|
if (subCategory) {
|
||||||
subCategory.notes.push(prNote);
|
subCategory.notes.push(prNote);
|
||||||
} else {
|
} else {
|
||||||
|
// No matching subcategory, add to main category
|
||||||
category.notes.push(prNote);
|
category.notes.push(prNote);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// No subcategories, add to main category
|
||||||
category.notes.push(prNote);
|
category.notes.push(prNote);
|
||||||
}
|
}
|
||||||
categorized = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return categorizedPRs;
|
return categorizedPRs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,12 +12,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
|||||||
|
|
||||||
## 2025-11-04
|
## 2025-11-04
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
|
||||||
|
|
||||||
- #### ✨ New Features
|
|
||||||
|
|
||||||
- stirling-pdf: add native jbig2 dep to installation script [@MickLesk](https://github.com/MickLesk) ([#8858](https://github.com/community-scripts/ProxmoxVE/pull/8858))
|
|
||||||
|
|
||||||
## 2025-11-03
|
## 2025-11-03
|
||||||
|
|
||||||
### 🆕 New Scripts
|
### 🆕 New Scripts
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
"ram": 2048,
|
"ram": 2048,
|
||||||
"hdd": 8,
|
"hdd": 8,
|
||||||
"os": "debian",
|
"os": "debian",
|
||||||
"version": "12"
|
"version": "13"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,74 +1,4 @@
|
|||||||
[
|
[
|
||||||
{
|
|
||||||
"name": "mattermost/mattermost",
|
|
||||||
"version": "v10.11.6",
|
|
||||||
"date": "2025-11-04T09:43:16Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "syncthing/syncthing",
|
|
||||||
"version": "v2.0.11",
|
|
||||||
"date": "2025-11-04T08:51:05Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "redis/redis",
|
|
||||||
"version": "8.4-rc1-int2",
|
|
||||||
"date": "2025-11-03T09:00:38Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "clusterzx/paperless-ai",
|
|
||||||
"version": "v3.0.9",
|
|
||||||
"date": "2025-11-04T07:28:45Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Jackett/Jackett",
|
|
||||||
"version": "v0.24.247",
|
|
||||||
"date": "2025-11-04T05:53:52Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "firefly-iii/firefly-iii",
|
|
||||||
"version": "v6.4.4",
|
|
||||||
"date": "2025-11-01T19:48:08Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "NginxProxyManager/nginx-proxy-manager",
|
|
||||||
"version": "v2.13.0",
|
|
||||||
"date": "2025-11-04T04:47:23Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "immich-app/immich",
|
|
||||||
"version": "v2.2.3",
|
|
||||||
"date": "2025-11-04T03:14:34Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "esphome/esphome",
|
|
||||||
"version": "2025.10.4",
|
|
||||||
"date": "2025-11-04T03:04:13Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "paperless-ngx/paperless-ngx",
|
|
||||||
"version": "v2.19.4",
|
|
||||||
"date": "2025-11-04T01:34:35Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "hyperion-project/hyperion.ng",
|
|
||||||
"version": "2.1.1",
|
|
||||||
"date": "2025-06-14T17:45:06Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "actualbudget/actual",
|
|
||||||
"version": "v25.11.0",
|
|
||||||
"date": "2025-11-04T00:32:21Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "jeedom/core",
|
|
||||||
"version": "4.4.20",
|
|
||||||
"date": "2025-11-04T00:27:08Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "steveiliop56/tinyauth",
|
|
||||||
"version": "v4.0.1",
|
|
||||||
"date": "2025-10-15T16:53:55Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "inventree/InvenTree",
|
"name": "inventree/InvenTree",
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
@@ -79,6 +9,11 @@
|
|||||||
"version": "v1.79.1.rc.2",
|
"version": "v1.79.1.rc.2",
|
||||||
"date": "2025-11-03T23:14:45Z"
|
"date": "2025-11-03T23:14:45Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "actualbudget/actual",
|
||||||
|
"version": "v25.11.0",
|
||||||
|
"date": "2025-11-03T23:12:18Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "gtsteffaniak/filebrowser",
|
"name": "gtsteffaniak/filebrowser",
|
||||||
"version": "v1.0.0-stable",
|
"version": "v1.0.0-stable",
|
||||||
@@ -89,6 +24,11 @@
|
|||||||
"version": "v0.29.0",
|
"version": "v0.29.0",
|
||||||
"date": "2025-11-03T20:10:26Z"
|
"date": "2025-11-03T20:10:26Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "firefly-iii/firefly-iii",
|
||||||
|
"version": "v6.4.4",
|
||||||
|
"date": "2025-11-01T19:48:08Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "azukaar/Cosmos-Server",
|
"name": "azukaar/Cosmos-Server",
|
||||||
"version": "v0.18.4",
|
"version": "v0.18.4",
|
||||||
@@ -149,15 +89,25 @@
|
|||||||
"version": "debian/12.1.34",
|
"version": "debian/12.1.34",
|
||||||
"date": "2025-11-03T16:42:07Z"
|
"date": "2025-11-03T16:42:07Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Sonarr/Sonarr",
|
||||||
|
"version": "v4.0.15.2941",
|
||||||
|
"date": "2025-06-20T17:20:54Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "keycloak/keycloak",
|
"name": "keycloak/keycloak",
|
||||||
"version": "26.0.17",
|
"version": "26.0.17",
|
||||||
"date": "2025-11-03T15:30:01Z"
|
"date": "2025-11-03T15:30:01Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Sonarr/Sonarr",
|
"name": "immich-app/immich",
|
||||||
"version": "v4.0.15.2941",
|
"version": "v2.2.2",
|
||||||
"date": "2025-06-20T17:20:54Z"
|
"date": "2025-11-03T15:10:24Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "clusterzx/paperless-ai",
|
||||||
|
"version": "v3.0.8",
|
||||||
|
"date": "2025-11-03T14:04:27Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "n8n-io/n8n",
|
"name": "n8n-io/n8n",
|
||||||
@@ -184,6 +134,11 @@
|
|||||||
"version": "v1.4.2",
|
"version": "v1.4.2",
|
||||||
"date": "2025-11-03T11:52:53Z"
|
"date": "2025-11-03T11:52:53Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "redis/redis",
|
||||||
|
"version": "8.4-rc1-int2",
|
||||||
|
"date": "2025-11-03T09:00:38Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "silverbulletmd/silverbullet",
|
"name": "silverbulletmd/silverbullet",
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
@@ -194,11 +149,31 @@
|
|||||||
"version": "fumadocs-mdx@13.0.5",
|
"version": "fumadocs-mdx@13.0.5",
|
||||||
"date": "2025-11-03T06:55:11Z"
|
"date": "2025-11-03T06:55:11Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Jackett/Jackett",
|
||||||
|
"version": "v0.24.244",
|
||||||
|
"date": "2025-11-03T05:55:23Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "jellyfin/jellyfin",
|
"name": "jellyfin/jellyfin",
|
||||||
"version": "v10.11.2",
|
"version": "v10.11.2",
|
||||||
"date": "2025-11-03T02:29:00Z"
|
"date": "2025-11-03T02:29:00Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "hyperion-project/hyperion.ng",
|
||||||
|
"version": "2.1.1",
|
||||||
|
"date": "2025-06-14T17:45:06Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "jeedom/core",
|
||||||
|
"version": "4.4.20",
|
||||||
|
"date": "2025-11-03T00:27:04Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "steveiliop56/tinyauth",
|
||||||
|
"version": "v4.0.1",
|
||||||
|
"date": "2025-10-15T16:53:55Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "maxdorninger/MediaManager",
|
"name": "maxdorninger/MediaManager",
|
||||||
"version": "v1.9.1",
|
"version": "v1.9.1",
|
||||||
@@ -217,7 +192,7 @@
|
|||||||
{
|
{
|
||||||
"name": "theonedev/onedev",
|
"name": "theonedev/onedev",
|
||||||
"version": "v13.0.10",
|
"version": "v13.0.10",
|
||||||
"date": "2025-11-02T02:47:45Z"
|
"date": "2025-11-01T02:08:01Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "9001/copyparty",
|
"name": "9001/copyparty",
|
||||||
@@ -314,6 +289,11 @@
|
|||||||
"version": "planka-1.1.1",
|
"version": "planka-1.1.1",
|
||||||
"date": "2025-10-31T12:38:47Z"
|
"date": "2025-10-31T12:38:47Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "mattermost/mattermost",
|
||||||
|
"version": "mattermost-redux@11.0.4",
|
||||||
|
"date": "2025-10-30T16:44:14Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "chrisvel/tududi",
|
"name": "chrisvel/tududi",
|
||||||
"version": "v0.85.1",
|
"version": "v0.85.1",
|
||||||
@@ -419,6 +399,11 @@
|
|||||||
"version": "v2.7.12",
|
"version": "v2.7.12",
|
||||||
"date": "2025-05-29T17:08:26Z"
|
"date": "2025-05-29T17:08:26Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "paperless-ngx/paperless-ngx",
|
||||||
|
"version": "v2.19.3",
|
||||||
|
"date": "2025-10-29T17:58:16Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "go-gitea/gitea",
|
"name": "go-gitea/gitea",
|
||||||
"version": "v1.25.0",
|
"version": "v1.25.0",
|
||||||
@@ -544,6 +529,11 @@
|
|||||||
"version": "e6.0.1-alpha.2",
|
"version": "e6.0.1-alpha.2",
|
||||||
"date": "2025-10-27T09:36:30Z"
|
"date": "2025-10-27T09:36:30Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "syncthing/syncthing",
|
||||||
|
"version": "v2.0.10",
|
||||||
|
"date": "2025-09-24T08:33:37Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Radarr/Radarr",
|
"name": "Radarr/Radarr",
|
||||||
"version": "v5.28.0.10274",
|
"version": "v5.28.0.10274",
|
||||||
@@ -599,6 +589,11 @@
|
|||||||
"version": "v0.31.0",
|
"version": "v0.31.0",
|
||||||
"date": "2025-10-24T04:07:27Z"
|
"date": "2025-10-24T04:07:27Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "esphome/esphome",
|
||||||
|
"version": "2025.10.3",
|
||||||
|
"date": "2025-10-24T01:08:22Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "drakkan/sftpgo",
|
"name": "drakkan/sftpgo",
|
||||||
"version": "v2.7.0",
|
"version": "v2.7.0",
|
||||||
@@ -1254,6 +1249,11 @@
|
|||||||
"version": "1.3.11",
|
"version": "1.3.11",
|
||||||
"date": "2025-07-13T13:33:48Z"
|
"date": "2025-07-13T13:33:48Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "NginxProxyManager/nginx-proxy-manager",
|
||||||
|
"version": "v2.12.6",
|
||||||
|
"date": "2025-07-09T21:52:15Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "photoprism/photoprism",
|
"name": "photoprism/photoprism",
|
||||||
"version": "250707-d28b3101e",
|
"version": "250707-d28b3101e",
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ $STD apt install -y \
|
|||||||
unpaper \
|
unpaper \
|
||||||
fonts-urw-base35 \
|
fonts-urw-base35 \
|
||||||
qpdf \
|
qpdf \
|
||||||
poppler-utils \
|
poppler-utils
|
||||||
jbig2
|
|
||||||
msg_ok "Installed Dependencies"
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
PYTHON_VERSION="3.12" setup_uv
|
PYTHON_VERSION="3.12" setup_uv
|
||||||
@@ -70,12 +69,24 @@ $STD uv pip install \
|
|||||||
ocrmypdf \
|
ocrmypdf \
|
||||||
pillow \
|
pillow \
|
||||||
pdf2image
|
pdf2image
|
||||||
|
|
||||||
$STD apt install -y python3-uno python3-pip
|
$STD apt install -y python3-uno python3-pip
|
||||||
$STD pip3 install --break-system-packages --timeout=120 unoserver
|
$STD pip3 install --break-system-packages unoserver
|
||||||
ln -sf /opt/.venv/bin/python3 /usr/local/bin/python3
|
ln -sf /opt/.venv/bin/python3 /usr/local/bin/python3
|
||||||
ln -sf /opt/.venv/bin/pip /usr/local/bin/pip
|
ln -sf /opt/.venv/bin/pip /usr/local/bin/pip
|
||||||
msg_ok "Installed Python Dependencies"
|
msg_ok "Installed Python Dependencies"
|
||||||
|
|
||||||
|
msg_info "Installing JBIG2"
|
||||||
|
$STD curl -fsSL -o /tmp/jbig2enc.tar.gz https://github.com/agl/jbig2enc/archive/refs/tags/0.30.tar.gz
|
||||||
|
mkdir -p /opt/jbig2enc
|
||||||
|
tar -xzf /tmp/jbig2enc.tar.gz -C /opt/jbig2enc --strip-components=1
|
||||||
|
cd /opt/jbig2enc
|
||||||
|
$STD bash ./autogen.sh
|
||||||
|
$STD bash ./configure
|
||||||
|
$STD make
|
||||||
|
$STD make install
|
||||||
|
msg_ok "Installed JBIG2"
|
||||||
|
|
||||||
msg_info "Installing Language Packs (Patience)"
|
msg_info "Installing Language Packs (Patience)"
|
||||||
$STD apt install -y 'tesseract-ocr-*'
|
$STD apt install -y 'tesseract-ocr-*'
|
||||||
msg_ok "Installed Language Packs"
|
msg_ok "Installed Language Packs"
|
||||||
|
|||||||
Reference in New Issue
Block a user