Merge branch 'config' into localApps
This commit is contained in:
commit
4802fe6f1a
|
|
@ -0,0 +1,131 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
def extract_version_from_string(input_string):
|
||||||
|
"""
|
||||||
|
从字符串中提取版本号,支持镜像名和文件夹名
|
||||||
|
|
||||||
|
Args:
|
||||||
|
input_string (str): 可以是Docker镜像名或文件夹名
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: 包含提取结果的字典 {success: bool, version: str}
|
||||||
|
"""
|
||||||
|
if ':' in input_string:
|
||||||
|
parts = input_string.split(':')
|
||||||
|
candidate = parts[-1]
|
||||||
|
else:
|
||||||
|
candidate = os.path.basename(input_string)
|
||||||
|
|
||||||
|
# 保存原始候选字符串用于失败时返回
|
||||||
|
original_candidate = candidate
|
||||||
|
|
||||||
|
# 标准的 major.minor.patch 格式(点号分隔)
|
||||||
|
pattern1 = r'(\d+\.\d+\.\d+)'
|
||||||
|
match1 = re.search(pattern1, candidate)
|
||||||
|
if match1:
|
||||||
|
return {"success": True, "version": match1.group(1)}
|
||||||
|
|
||||||
|
# 连字符分隔的版本号 major-minor-patch
|
||||||
|
pattern2 = r'(\d+\-\d+\-\d+)'
|
||||||
|
match2 = re.search(pattern2, candidate)
|
||||||
|
if match2:
|
||||||
|
# 将连字符转换为点号
|
||||||
|
version_with_dots = match2.group(1).replace('-', '.')
|
||||||
|
return {"success": True, "version": version_with_dots}
|
||||||
|
|
||||||
|
# 混合分隔符(如 major.minor-patch)
|
||||||
|
pattern3 = r'(\d+[\.\-]\d+[\.\-]\d+)'
|
||||||
|
match3 = re.search(pattern3, candidate)
|
||||||
|
if match3:
|
||||||
|
# 将所有分隔符统一为点号
|
||||||
|
version_mixed = match3.group(1)
|
||||||
|
version_normalized = re.sub(r'[\.\-]', '.', version_mixed)
|
||||||
|
return {"success": True, "version": version_normalized}
|
||||||
|
|
||||||
|
# 两个部分的版本号 (major.minor 或 major-minor)
|
||||||
|
pattern4 = r'(\d+[\.\-]\d+)(?![\.\-]\d)' # 确保后面没有第三个数字部分
|
||||||
|
match4 = re.search(pattern4, candidate)
|
||||||
|
if match4:
|
||||||
|
version_two_part = match4.group(1)
|
||||||
|
version_normalized = re.sub(r'[\.\-]', '.', version_two_part)
|
||||||
|
return {"success": True, "version": version_normalized}
|
||||||
|
|
||||||
|
# 从复杂标签中提取包含数字和分隔符的版本号部分
|
||||||
|
pattern5 = r'(\d+(?:[\.\-]\d+)+)'
|
||||||
|
matches = re.findall(pattern5, candidate)
|
||||||
|
if matches:
|
||||||
|
# 选择最长的匹配项,并统一分隔符为点号
|
||||||
|
best_match = max(matches, key=len)
|
||||||
|
normalized_version = re.sub(r'[\.\-]', '.', best_match)
|
||||||
|
return {"success": True, "version": normalized_version}
|
||||||
|
|
||||||
|
return {"success": False, "version": original_candidate}
|
||||||
|
|
||||||
|
def replace_version_in_dirname(old_ver_dir, new_version):
|
||||||
|
"""
|
||||||
|
将旧版本文件夹名中的版本号替换为新版本号
|
||||||
|
|
||||||
|
Args:
|
||||||
|
old_ver_dir (str): 旧版本文件夹名
|
||||||
|
new_version (str): 新版本号
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 新版本文件夹名
|
||||||
|
"""
|
||||||
|
version_info = extract_version_from_string(old_ver_dir)
|
||||||
|
|
||||||
|
if version_info["success"]:
|
||||||
|
old_version = version_info["original"]
|
||||||
|
new_ver_dir = old_ver_dir.replace(old_version, new_version)
|
||||||
|
return new_ver_dir
|
||||||
|
else:
|
||||||
|
return new_version
|
||||||
|
|
||||||
|
def main():
|
||||||
|
app_name = sys.argv[1]
|
||||||
|
old_ver_dir = sys.argv[2]
|
||||||
|
|
||||||
|
docker_compose_file = f"apps/{app_name}/{old_ver_dir}/docker-compose.yml"
|
||||||
|
|
||||||
|
if not os.path.exists(docker_compose_file):
|
||||||
|
print(f"错误: 文件 {docker_compose_file} 不存在")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with open(docker_compose_file, 'r') as f:
|
||||||
|
compose_data = yaml.safe_load(f)
|
||||||
|
|
||||||
|
services = compose_data.get('services', {})
|
||||||
|
|
||||||
|
first_service = list(services.keys())[0]
|
||||||
|
print(f"第一个服务是: {first_service}")
|
||||||
|
|
||||||
|
image = services[first_service].get('image', '')
|
||||||
|
print(f"该服务的镜像: {image}")
|
||||||
|
|
||||||
|
new_version = extract_version_from_string(image)
|
||||||
|
print(f"版本号: {new_version}")
|
||||||
|
|
||||||
|
old_version = extract_version_from_string(old_ver_dir)
|
||||||
|
new_ver_dir = replace_version_in_dirname(old_ver_dir, new_version)
|
||||||
|
if old_version != new_version:
|
||||||
|
old_path = f"apps/{app_name}/{old_ver_dir}"
|
||||||
|
new_path = f"apps/{app_name}/{new_ver_dir}"
|
||||||
|
|
||||||
|
if not os.path.exists(new_path):
|
||||||
|
print(f"将 {old_path} 重命名为 {new_path}")
|
||||||
|
shutil.move(old_path, new_path)
|
||||||
|
|
||||||
|
version_file = f"apps/{app_name}/{old_version}.version"
|
||||||
|
with open(version_file, 'w') as f:
|
||||||
|
f.write(new_version)
|
||||||
|
else:
|
||||||
|
print(f"错误: {new_path} 文件夹已存在")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# This script copies the version from docker-compose.yml to config.json.
|
|
||||||
|
|
||||||
app_name=$1
|
|
||||||
old_version=$2
|
|
||||||
|
|
||||||
# find all docker-compose files under apps/$app_name (there should be only one)
|
|
||||||
docker_compose_files=$(find apps/$app_name/$old_version -name docker-compose.yml)
|
|
||||||
|
|
||||||
for docker_compose_file in $docker_compose_files
|
|
||||||
do
|
|
||||||
# Assuming that the app version will be from the first docker image
|
|
||||||
first_service=$(yq '.services | keys | .[0]' $docker_compose_file)
|
|
||||||
echo "第一个服务是: $first_service"
|
|
||||||
|
|
||||||
image=$(yq .services.$first_service.image $docker_compose_file)
|
|
||||||
echo "该服务的镜像: $image"
|
|
||||||
|
|
||||||
# Only apply changes if the format is <image>:<version>
|
|
||||||
if [[ "$image" == *":"* ]]; then
|
|
||||||
version=$(cut -d ":" -f2- <<< "$image")
|
|
||||||
echo "版本号: $version"
|
|
||||||
|
|
||||||
# Trim the "v" prefix
|
|
||||||
trimmed_version=${version/#"v"}
|
|
||||||
echo "Trimmed version: $trimmed_version"
|
|
||||||
if [ "$old_version" != "$trimmed_version" ]; then
|
|
||||||
echo "将 apps/$app_name/$old_version 重命名为 apps/$app_name/$trimmed_version"
|
|
||||||
if [ ! -d "apps/$app_name/$trimmed_version" ]; then
|
|
||||||
mv apps/$app_name/$old_version apps/$app_name/$trimmed_version
|
|
||||||
echo "$trimmed_version" > apps/$app_name/${old_version}.version
|
|
||||||
else
|
|
||||||
echo "apps/$app_name/$trimmed_version 文件夹已存在"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
@ -1,11 +1,42 @@
|
||||||
name: Update app version in Renovate Branches
|
name: App Version CI/CD
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
pull_request:
|
||||||
branches: [ 'renovate/*' ]
|
types:
|
||||||
|
- opened
|
||||||
|
- synchronize
|
||||||
|
- reopened
|
||||||
|
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
get-latest-commit-author:
|
||||||
|
name: Get Latest Commit Author
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
latest_commit_author: ${{ steps.latest-commit-author.outputs.latest_commit_author }}
|
||||||
|
steps:
|
||||||
|
- name: Get latest commit author
|
||||||
|
id: latest-commit-author
|
||||||
|
run: |
|
||||||
|
resp=$(gh api \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||||
|
/repos/${{ github.repository}}/commits/${{ github.event.pull_request.head.ref }})
|
||||||
|
author=$(echo "$resp" | jq -r '.author.login // empty')
|
||||||
|
echo "the Author of Latest Commit on Head Branch: $author"
|
||||||
|
echo "latest_commit_author=$author" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
update-app-version:
|
update-app-version:
|
||||||
|
name: Update App Version
|
||||||
|
needs: get-latest-commit-author
|
||||||
|
if: |
|
||||||
|
github.actor == 'renovate[bot]' &&
|
||||||
|
github.triggering_actor == 'renovate[bot]' &&
|
||||||
|
needs.get-latest-commit-author.outputs.latest_commit_author != github.repository_owner &&
|
||||||
|
startsWith(github.head_ref, 'renovate/')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
@ -16,11 +47,15 @@ jobs:
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: actions/setup-python@main
|
||||||
|
with:
|
||||||
|
python-version: 3.x
|
||||||
|
pip-install: PyYAML
|
||||||
|
|
||||||
- name: Configure repo
|
- name: Configure repo
|
||||||
run: |
|
run: |
|
||||||
git config --local user.email "githubaction@githubaction.com"
|
git config --local user.email "githubaction@githubaction.com"
|
||||||
git config --local user.name "github-action"
|
git config --local user.name "github-action"
|
||||||
gh auth login --with-token <<< "${{ github.token }}"
|
|
||||||
|
|
||||||
- name: Get list of updated files by the last commit in this branch separated by space
|
- name: Get list of updated files by the last commit in this branch separated by space
|
||||||
id: updated-files
|
id: updated-files
|
||||||
|
|
@ -35,8 +70,8 @@ jobs:
|
||||||
if [[ $file == *"docker-compose.yml"* ]]; then
|
if [[ $file == *"docker-compose.yml"* ]]; then
|
||||||
app_name=$(echo $file | cut -d'/' -f 2)
|
app_name=$(echo $file | cut -d'/' -f 2)
|
||||||
old_version=$(echo $file | cut -d'/' -f 3)
|
old_version=$(echo $file | cut -d'/' -f 3)
|
||||||
chmod +x .github/workflows/renovate-app-version.sh
|
chmod +x .github/workflows/renovate-app-version.py
|
||||||
.github/workflows/renovate-app-version.sh $app_name $old_version
|
python3 .github/workflows/renovate-app-version.py $app_name $old_version
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
@ -61,4 +96,77 @@ jobs:
|
||||||
-f 'context=${{ github.workflow}}'
|
-f 'context=${{ github.workflow}}'
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
check-labels:
|
||||||
|
name: Check labels
|
||||||
|
if: |
|
||||||
|
github.actor == 'renovate[bot]' &&
|
||||||
|
github.triggering_actor == 'renovate[bot]'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
enable: ${{ steps.check-labels.outputs.enable }}
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: Check for major label
|
||||||
|
id: check-labels
|
||||||
|
run: |
|
||||||
|
pr_labels='${{ join(github.event.pull_request.labels.*.name, ',') }}'
|
||||||
|
if [[ $pr_labels =~ "major" ]]; then
|
||||||
|
echo "❌ PR has major label"
|
||||||
|
echo "enable=false" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "✅ PR does not have major label"
|
||||||
|
echo "enable=true" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Add reviewer and comment for major PR
|
||||||
|
if: steps.check-labels.outputs.enable == 'false'
|
||||||
|
run: |
|
||||||
|
gh pr edit $PR_NUMBER --add-reviewer ${{ github.actor }}
|
||||||
|
gh pr edit $PR_NUMBER --add-assignee ${{ github.actor }}
|
||||||
|
|
||||||
|
- name: remove labels
|
||||||
|
run: |
|
||||||
|
pr_labels='${{ join(github.event.pull_request.labels.*.name, ',') }}'
|
||||||
|
IFS=',' read -ra labels_array <<< "$pr_labels"
|
||||||
|
for label in "${labels_array[@]}"; do
|
||||||
|
echo "Removing label: $label"
|
||||||
|
gh pr edit $PR_NUMBER --remove-label="$label"
|
||||||
|
done
|
||||||
|
|
||||||
|
merge-prs:
|
||||||
|
name: Auto Merge the PR
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- update-app-version
|
||||||
|
- check-labels
|
||||||
|
if: |
|
||||||
|
needs.check-labels.outputs.enable == 'true' &&
|
||||||
|
(needs.update-app-version.result == 'success' || needs.update-app-version.result == 'skipped')
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
ref: ${{ github.base_ref }}
|
||||||
|
|
||||||
|
- name: Merge PR
|
||||||
|
run: |
|
||||||
|
max_attempts=5
|
||||||
|
for attempt in $(seq 1 $max_attempts); do
|
||||||
|
if gh pr merge $PR_NUMBER --squash --delete-branch --body ""; then
|
||||||
|
echo "✅ Merge PR #$PR_NUMBER Success"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "⚠️ Merge PR #$PR_NUMBER Failed ($attempt / $max_attempts)"
|
||||||
|
sleep 5
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,24 @@
|
||||||
"extends": [
|
"extends": [
|
||||||
"config:recommended"
|
"config:recommended"
|
||||||
],
|
],
|
||||||
"reviewers": ["pooneyy"],
|
|
||||||
"gitIgnoredAuthors": [
|
"gitIgnoredAuthors": [
|
||||||
"githubaction@githubaction.com",
|
"githubaction@githubaction.com",
|
||||||
"85266337+pooneyy@users.noreply.github.com"
|
"85266337+pooneyy@users.noreply.github.com"
|
||||||
],
|
],
|
||||||
"automerge": true,
|
"prBodyColumns": [
|
||||||
"automergeType": "pr",
|
"Package",
|
||||||
"automergeStrategy": "squash",
|
"Update",
|
||||||
|
"Change",
|
||||||
|
"Pending"
|
||||||
|
],
|
||||||
"rebaseWhen": "never",
|
"rebaseWhen": "never",
|
||||||
"packageRules": [
|
"packageRules": [
|
||||||
{
|
{
|
||||||
"matchPackageNames": [
|
"matchUpdateTypes": ["major", "minor", "patch", "pin", "pinDigest", "digest", "lockFileMaintenance", "rollback", "bump", "replacement"],
|
||||||
|
"addLabels": ["{{ updateType }}"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matchManagers": [
|
||||||
"docker-compose"
|
"docker-compose"
|
||||||
],
|
],
|
||||||
"automerge": true
|
"automerge": true
|
||||||
|
|
@ -150,9 +156,9 @@
|
||||||
"allowedVersions": "<2"
|
"allowedVersions": "<2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"matchPackageNames": ["xhofe/alist"],
|
"matchPackageNames": ["xhofe/alist**"],
|
||||||
"matchCurrentVersion": "v3.40.0",
|
"matchCurrentVersion": "/^v3.40.*/",
|
||||||
"allowedVersions": "v3.40.0"
|
"enabled": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"matchPackageNames": ["yisier1/npc", "yisier1/nps"],
|
"matchPackageNames": ["yisier1/npc", "yisier1/nps"],
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue