Skip to content

Commit aa3cf49

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents f7f2df0 + eaab944 commit aa3cf49

File tree

5 files changed

+625
-1
lines changed

5 files changed

+625
-1
lines changed

.github/workflows/auto-merge.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
on: pull_request_target
2+
3+
name: pull_request_target
4+
5+
permissions:
6+
pull-requests: write
7+
contents: write
8+
9+
jobs:
10+
metadata:
11+
runs-on: ubuntu-latest
12+
13+
outputs:
14+
repository: ${{ steps.metadata.outputs.repository }}
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- uses: ahmadnassri/action-metadata@v2
20+
id: metadata
21+
22+
auto-merge:
23+
timeout-minutes: 5
24+
25+
runs-on: ubuntu-latest
26+
27+
# only run for dependabot PRs
28+
if: ${{ github.actor == 'dependabot[bot]' }}
29+
30+
env:
31+
PR_URL: ${{github.event.pull_request.html_url}}
32+
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
33+
34+
steps:
35+
- id: dependabot
36+
uses: dependabot/fetch-metadata@v2
37+
with:
38+
github-token: ${{ secrets.GITHUB_TOKEN }}
39+
40+
- name: auto merge conditions
41+
id: auto-merge
42+
if: |
43+
(
44+
steps.dependabot.outputs.update-type == 'version-update:semver-patch' &&
45+
contains('direct:production,indirect:production', steps.dependabot.outputs.dependency-type)
46+
) || (
47+
steps.dependabot.outputs.update-type == 'version-update:semver-minor' &&
48+
contains('direct:development,indirect:development', steps.dependabot.outputs.dependency-type)
49+
)
50+
run: echo "::notice ::auto-merge conditions satisfied"
51+
52+
- name: auto approve pr
53+
if: ${{ steps.auto-merge.conclusion == 'success' }}
54+
run: |
55+
gh pr review --approve "$PR_URL"
56+
gh pr merge --auto --rebase "$PR_URL"
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Create labels
2+
3+
on:
4+
push:
5+
branches:
6+
- 'main'
7+
8+
jobs:
9+
labeler:
10+
runs-on: ubuntu-latest
11+
steps:
12+
-
13+
name: Checkout
14+
uses: actions/checkout@v3
15+
-
16+
name: Run Labeler
17+
if: success()
18+
uses: crazy-max/ghaction-github-labeler@v4
19+
with:
20+
github-token: ${{ secrets.GITHUB_TOKEN }}
21+
yaml-file: .github/labels.yml
22+
skip-delete: false
23+
dry-run: false
24+
exclude: |
25+
help*
26+
*issue
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
name: Update Releases Properties
2+
3+
# This workflow runs in individual module repositories (e.g., module-php)
4+
# It automatically updates releases.properties file when a release is published
5+
6+
on:
7+
release:
8+
types: [prereleased, released, edited]
9+
10+
# Manual trigger for testing
11+
workflow_dispatch:
12+
inputs:
13+
release_tag:
14+
description: 'Release tag to process (e.g., 2025.10.31)'
15+
required: true
16+
17+
jobs:
18+
update-properties:
19+
runs-on: ubuntu-latest
20+
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v4
24+
with:
25+
token: ${{ secrets.GH_PAT }}
26+
27+
- name: Set up Python
28+
uses: actions/setup-python@v5
29+
with:
30+
python-version: '3.11'
31+
32+
- name: Install dependencies
33+
run: |
34+
pip install requests packaging
35+
36+
- name: Extract module name from repository
37+
id: extract_module
38+
run: |
39+
# Extract module name from repo name (e.g., "module-php" -> "php")
40+
REPO_NAME="${{ github.event.repository.name }}"
41+
echo "Repository name: ${REPO_NAME}"
42+
43+
# Remove "module-" prefix (case-insensitive)
44+
if [[ "${REPO_NAME}" == module-* ]]; then
45+
MODULE_NAME="${REPO_NAME#module-}"
46+
elif [[ "${REPO_NAME}" == Module-* ]]; then
47+
MODULE_NAME="${REPO_NAME#Module-}"
48+
else
49+
echo "ERROR: Repository name does not start with 'module-'"
50+
echo "Expected format: module-MODULENAME (e.g., module-php)"
51+
exit 1
52+
fi
53+
54+
# Convert to lowercase
55+
MODULE_NAME=$(echo "${MODULE_NAME}" | tr '[:upper:]' '[:lower:]')
56+
57+
echo "module_name=${MODULE_NAME}" >> $GITHUB_OUTPUT
58+
echo "Module name: ${MODULE_NAME}"
59+
60+
- name: Update releases properties
61+
env:
62+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63+
RELEASE_TAG: ${{ github.event.release.tag_name || github.event.inputs.release_tag }}
64+
REPO_OWNER: ${{ github.repository_owner }}
65+
REPO_NAME: ${{ github.event.repository.name }}
66+
MODULE_NAME: ${{ steps.extract_module.outputs.module_name }}
67+
run: |
68+
python << 'EOF'
69+
import os
70+
import re
71+
import requests
72+
from packaging import version
73+
from collections import OrderedDict
74+
75+
# Get environment variables
76+
release_tag = os.environ['RELEASE_TAG']
77+
repo_owner = os.environ['REPO_OWNER']
78+
repo_name = os.environ['REPO_NAME']
79+
module_name = os.environ['MODULE_NAME']
80+
github_token = os.environ['GITHUB_TOKEN']
81+
82+
# Strip module name prefix from tag if present (e.g., "postgresql-2025.11.22" -> "2025.11.22")
83+
if release_tag.lower().startswith(f"{module_name.lower()}-"):
84+
original_tag = release_tag
85+
release_tag = release_tag[len(module_name)+1:]
86+
print(f"Stripped module prefix from tag: {original_tag} -> {release_tag}")
87+
88+
print(f"Processing release: {release_tag}")
89+
print(f"Module name: {module_name}")
90+
91+
# Construct API URL
92+
api_url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/releases/tags/{release_tag}"
93+
94+
headers = {
95+
'Authorization': f'token {github_token}',
96+
'Accept': 'application/vnd.github.v3+json'
97+
}
98+
99+
print(f"Fetching release information from: {api_url}")
100+
101+
# Fetch release data
102+
response = requests.get(api_url, headers=headers)
103+
response.raise_for_status()
104+
release_data = response.json()
105+
106+
# Extract assets that end with .7z only
107+
assets = []
108+
109+
# Use bearsampp-module format as the filename prefix (e.g., "bearsampp-postgresql")
110+
filename_prefix = f"bearsampp-{module_name}"
111+
112+
print(f"Looking for .7z files with prefix: {filename_prefix}")
113+
print(f"Available assets:")
114+
for asset in release_data.get('assets', []):
115+
print(f" - {asset['name']}")
116+
117+
for asset in release_data.get('assets', []):
118+
filename = asset['name']
119+
120+
# Check if file ends with .7z
121+
if filename.endswith('.7z'):
122+
download_url = asset['browser_download_url']
123+
124+
# Extract version number after filename prefix (e.g., "bearsampp-apache-2.4.66-2025.12.8.7z" -> "2.4.66")
125+
# Pattern: filename_prefix followed by version, then either a dash+date or .7z
126+
# Supports: 18.1, 17.2.3, 3.2.1.0, 17.0-RC1, 2.4.62
127+
# The lookahead ensures we stop before a date pattern or .7z extension
128+
version_match = re.search(
129+
rf'{filename_prefix}-(\d+\.\d+(?:\.\d+)?(?:\.\d+)?(?:-(?:RC|beta|alpha|dev)\d*)?)(?=-20\d{{2}}\.\d{{1,2}}\.\d{{1,2}}|\.7z|$)',
130+
filename,
131+
re.IGNORECASE
132+
)
133+
if version_match:
134+
ver = version_match.group(1)
135+
assets.append({
136+
'version': ver,
137+
'url': download_url,
138+
'filename': filename
139+
})
140+
print(f"Found: {filename} -> Version: {ver}")
141+
else:
142+
print(f"Warning: Could not extract version from: {filename}")
143+
# Debug: print the filename for troubleshooting
144+
print(f" Filename: {filename}")
145+
print(f" Looking for prefix: {filename_prefix}")
146+
147+
if not assets:
148+
print(f"No .7z assets found in release")
149+
exit(0)
150+
151+
# Read existing properties file
152+
properties_file = "releases.properties"
153+
154+
if not os.path.exists(properties_file):
155+
print(f"Properties file not found: {properties_file}")
156+
print(f"Creating new properties file...")
157+
with open(properties_file, 'w', encoding='utf-8') as f:
158+
f.write(f"# {module_name.upper()} Releases Properties\n")
159+
f.write(f"# Auto-generated and maintained by automation\n\n")
160+
161+
with open(properties_file, 'r', encoding='utf-8') as f:
162+
lines = f.readlines()
163+
164+
# Parse existing properties
165+
properties = OrderedDict()
166+
header_lines = []
167+
in_header = True
168+
169+
for line in lines:
170+
stripped = line.strip()
171+
if in_header and (stripped.startswith('#') or stripped == ''):
172+
header_lines.append(line)
173+
else:
174+
in_header = False
175+
if '=' in line and not stripped.startswith('#'):
176+
key, value = line.split('=', 1)
177+
properties[key.strip()] = value.strip()
178+
179+
# Fix malformed version entries by re-extracting correct versions from URLs
180+
# This handles cases like "2025.7.2.7" or "18.1-2025" that should be "18.1"
181+
fixed_properties = OrderedDict()
182+
for key, url in properties.items():
183+
# Try to extract the correct version from the URL
184+
# URL format: .../bearsampp-apache-2.4.66-2025.12.8.7z (for apache)
185+
# URL format: .../bearsampp-postgresql-18.1-2025.12.8.7z (for other modules)
186+
url_version_match = re.search(
187+
rf'{filename_prefix}-(\d+\.\d+(?:\.\d+)?(?:\.\d+)?(?:-(?:RC|beta|alpha|dev)\d*)?)(?=-20\d{{2}}\.\d{{1,2}}\.\d{{1,2}}|\.7z|/|$)',
188+
url,
189+
re.IGNORECASE
190+
)
191+
192+
if url_version_match:
193+
correct_version = url_version_match.group(1)
194+
# If the key is malformed (date-like or has trailing year), fix it
195+
if re.match(r'^20\d{2}\.', key) or re.search(r'-20\d{2}$', key):
196+
print(f"Fixing malformed entry: {key} -> {correct_version}")
197+
fixed_properties[correct_version] = url
198+
else:
199+
# Keep valid entries as-is
200+
fixed_properties[key] = url
201+
else:
202+
# If we can't extract version from URL, keep the original entry
203+
fixed_properties[key] = url
204+
205+
properties = fixed_properties
206+
207+
# Add new versions
208+
for asset in assets:
209+
ver = asset['version']
210+
url = asset['url']
211+
212+
# Create property key (just version number)
213+
key = ver
214+
properties[key] = url
215+
print(f"Added/Updated: {key} = {url}")
216+
217+
# Sort properties by version (semver)
218+
def extract_version(key):
219+
# Parse version directly from key
220+
try:
221+
return version.parse(key)
222+
except:
223+
return version.parse("0.0.0")
224+
225+
sorted_properties = OrderedDict(
226+
sorted(properties.items(), key=lambda x: extract_version(x[0]), reverse=True)
227+
)
228+
229+
# Write back to file
230+
with open(properties_file, 'w', encoding='utf-8') as f:
231+
# Write header
232+
for line in header_lines:
233+
f.write(line)
234+
235+
# Write sorted properties with spaces around equals sign
236+
for key, value in sorted_properties.items():
237+
f.write(f"{key} = {value}\n")
238+
239+
print(f"\nSuccessfully updated {properties_file}")
240+
print(f"Total versions: {len(sorted_properties)}")
241+
242+
EOF
243+
244+
- name: Create Pull Request
245+
id: create_pr
246+
uses: peter-evans/create-pull-request@v6
247+
with:
248+
token: ${{ secrets.GH_PAT }}
249+
base: main
250+
commit-message: |
251+
Update releases.properties
252+
253+
Auto-generated from release ${{ github.event.release.tag_name || github.event.inputs.release_tag }}
254+
branch: update-releases-${{ github.event.release.tag_name || github.event.inputs.release_tag }}
255+
delete-branch: true
256+
title: 'Update releases.properties from release ${{ github.event.release.tag_name || github.event.inputs.release_tag }}'
257+
body: |
258+
## 🤖 Automated Releases Properties Update
259+
260+
This PR updates the `releases.properties` file with new versions from release `${{ github.event.release.tag_name || github.event.inputs.release_tag }}`.
261+
262+
### Changes:
263+
- Extracted .7z assets from the release
264+
- Added version entries with download URLs
265+
- Maintained semver ordering (newest first)
266+
267+
**Release URL:** ${{ github.event.release.html_url || format('https://github.com/{0}/{1}/releases/tag/{2}', github.repository_owner, github.event.repository.name, github.event.inputs.release_tag) }}
268+
269+
### Next Steps:
270+
1. ⏳ Link validation will run automatically
271+
2. ✅ Once validation passes, this PR will auto-merge
272+
3. ❌ If validation fails, please review and fix invalid URLs
273+
labels: |
274+
automated
275+
releases-update
276+
277+
- name: Wait for validation checks
278+
if: steps.create_pr.outputs.pull-request-number != ''
279+
run: |
280+
echo "Waiting for link validation to complete..."
281+
sleep 10
282+
283+
- name: Enable auto-merge
284+
if: steps.create_pr.outputs.pull-request-number != ''
285+
run: |
286+
gh pr merge ${{ steps.create_pr.outputs.pull-request-number }} --auto --squash
287+
env:
288+
GH_TOKEN: ${{ secrets.GH_PAT }}

0 commit comments

Comments
 (0)