PowerShell 7.5.4 #20
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Update Releases Properties | |
| # This workflow runs in individual module repositories (e.g., module-php) | |
| # It automatically updates releases.properties file when a release is published | |
| on: | |
| release: | |
| types: [prereleased, released, edited] | |
| # Manual trigger for testing | |
| workflow_dispatch: | |
| inputs: | |
| release_tag: | |
| description: 'Release tag to process (e.g., 2025.10.31)' | |
| required: true | |
| jobs: | |
| update-properties: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ secrets.GH_PAT }} | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install dependencies | |
| run: | | |
| pip install requests packaging | |
| - name: Extract module name from repository | |
| id: extract_module | |
| run: | | |
| # Extract module name from repo name (e.g., "module-php" -> "php") | |
| REPO_NAME="${{ github.event.repository.name }}" | |
| echo "Repository name: ${REPO_NAME}" | |
| # Remove "module-" prefix (case-insensitive) | |
| if [[ "${REPO_NAME}" == module-* ]]; then | |
| MODULE_NAME="${REPO_NAME#module-}" | |
| elif [[ "${REPO_NAME}" == Module-* ]]; then | |
| MODULE_NAME="${REPO_NAME#Module-}" | |
| else | |
| echo "ERROR: Repository name does not start with 'module-'" | |
| echo "Expected format: module-MODULENAME (e.g., module-php)" | |
| exit 1 | |
| fi | |
| # Convert to lowercase | |
| MODULE_NAME=$(echo "${MODULE_NAME}" | tr '[:upper:]' '[:lower:]') | |
| echo "module_name=${MODULE_NAME}" >> $GITHUB_OUTPUT | |
| echo "Module name: ${MODULE_NAME}" | |
| - name: Update releases properties | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| RELEASE_TAG: ${{ github.event.release.tag_name || github.event.inputs.release_tag }} | |
| REPO_OWNER: ${{ github.repository_owner }} | |
| REPO_NAME: ${{ github.event.repository.name }} | |
| MODULE_NAME: ${{ steps.extract_module.outputs.module_name }} | |
| run: | | |
| python << 'EOF' | |
| import os | |
| import re | |
| import requests | |
| from packaging import version | |
| from collections import OrderedDict | |
| # Get environment variables | |
| release_tag = os.environ['RELEASE_TAG'] | |
| repo_owner = os.environ['REPO_OWNER'] | |
| repo_name = os.environ['REPO_NAME'] | |
| module_name = os.environ['MODULE_NAME'] | |
| github_token = os.environ['GITHUB_TOKEN'] | |
| # Strip module name prefix from tag if present (e.g., "postgresql-2025.11.22" -> "2025.11.22") | |
| if release_tag.lower().startswith(f"{module_name.lower()}-"): | |
| original_tag = release_tag | |
| release_tag = release_tag[len(module_name)+1:] | |
| print(f"Stripped module prefix from tag: {original_tag} -> {release_tag}") | |
| print(f"Processing release: {release_tag}") | |
| print(f"Module name: {module_name}") | |
| # Construct API URL | |
| api_url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/releases/tags/{release_tag}" | |
| headers = { | |
| 'Authorization': f'token {github_token}', | |
| 'Accept': 'application/vnd.github.v3+json' | |
| } | |
| print(f"Fetching release information from: {api_url}") | |
| # Fetch release data | |
| response = requests.get(api_url, headers=headers) | |
| response.raise_for_status() | |
| release_data = response.json() | |
| # Extract assets that end with .7z only | |
| assets = [] | |
| for asset in release_data.get('assets', []): | |
| filename = asset['name'] | |
| # Check if file ends with .7z | |
| if filename.endswith('.7z'): | |
| download_url = asset['browser_download_url'] | |
| # Extract version number after module name (e.g., "bearsampp-postgresql-18.1-2025.7.2.7z" -> "18.1") | |
| # Pattern: module_name followed by version, then either a dash+date or .7z | |
| # Supports: 18.1, 17.2.3, 3.2.1.0, 17.0-RC1 | |
| # The (?=-\d{4}\.|\.7z) ensures we stop before a date pattern or .7z extension | |
| version_match = re.search( | |
| rf'{module_name}-(\d+\.\d+(?:\.\d+)?(?:\.\d+)?(?:-(?:RC|beta|alpha|dev)\d*)?)(?=-\d{{4}}\.|-\d{{4}}\d{{2}}\.|\.\d+z|$)', | |
| filename, | |
| re.IGNORECASE | |
| ) | |
| if version_match: | |
| ver = version_match.group(1) | |
| assets.append({ | |
| 'version': ver, | |
| 'url': download_url, | |
| 'filename': filename | |
| }) | |
| print(f"Found: {filename} -> Version: {ver}") | |
| else: | |
| print(f"Warning: Could not extract version from: {filename}") | |
| if not assets: | |
| print(f"No .7z assets found in release") | |
| exit(0) | |
| # Read existing properties file | |
| properties_file = "releases.properties" | |
| if not os.path.exists(properties_file): | |
| print(f"Properties file not found: {properties_file}") | |
| print(f"Creating new properties file...") | |
| with open(properties_file, 'w', encoding='utf-8') as f: | |
| f.write(f"# {module_name.upper()} Releases Properties\n") | |
| f.write(f"# Auto-generated and maintained by automation\n\n") | |
| with open(properties_file, 'r', encoding='utf-8') as f: | |
| lines = f.readlines() | |
| # Parse existing properties | |
| properties = OrderedDict() | |
| header_lines = [] | |
| in_header = True | |
| for line in lines: | |
| stripped = line.strip() | |
| if in_header and (stripped.startswith('#') or stripped == ''): | |
| header_lines.append(line) | |
| else: | |
| in_header = False | |
| if '=' in line and not stripped.startswith('#'): | |
| key, value = line.split('=', 1) | |
| properties[key.strip()] = value.strip() | |
| # Fix malformed version entries by re-extracting correct versions from URLs | |
| # This handles cases like "2025.7.2.7" or "18.1-2025" that should be "18.1" | |
| fixed_properties = OrderedDict() | |
| for key, url in properties.items(): | |
| # Try to extract the correct version from the URL | |
| # URL format: .../bearsampp-postgresql-18.1-2025.7.2.7z | |
| url_version_match = re.search( | |
| rf'{module_name}-(\d+\.\d+(?:\.\d+)?(?:\.\d+)?(?:-(?:RC|beta|alpha|dev)\d*)?)(?=-\d{{4}}\.|-\d{{4}}\d{{2}}\.|\.\d+z|/|$)', | |
| url, | |
| re.IGNORECASE | |
| ) | |
| if url_version_match: | |
| correct_version = url_version_match.group(1) | |
| # If the key is malformed (date-like or has trailing year), fix it | |
| if re.match(r'^20\d{2}\.', key) or re.search(r'-20\d{2}$', key): | |
| print(f"Fixing malformed entry: {key} -> {correct_version}") | |
| fixed_properties[correct_version] = url | |
| else: | |
| # Keep valid entries as-is | |
| fixed_properties[key] = url | |
| else: | |
| # If we can't extract version from URL, keep the original entry | |
| fixed_properties[key] = url | |
| properties = fixed_properties | |
| # Add new versions | |
| for asset in assets: | |
| ver = asset['version'] | |
| url = asset['url'] | |
| # Create property key (just version number) | |
| key = ver | |
| properties[key] = url | |
| print(f"Added/Updated: {key} = {url}") | |
| # Sort properties by version (semver) | |
| def extract_version(key): | |
| # Parse version directly from key | |
| try: | |
| return version.parse(key) | |
| except: | |
| return version.parse("0.0.0") | |
| sorted_properties = OrderedDict( | |
| sorted(properties.items(), key=lambda x: extract_version(x[0]), reverse=True) | |
| ) | |
| # Write back to file | |
| with open(properties_file, 'w', encoding='utf-8') as f: | |
| # Write header | |
| for line in header_lines: | |
| f.write(line) | |
| # Write sorted properties with spaces around equals sign | |
| for key, value in sorted_properties.items(): | |
| f.write(f"{key} = {value}\n") | |
| print(f"\nSuccessfully updated {properties_file}") | |
| print(f"Total versions: {len(sorted_properties)}") | |
| EOF | |
| - name: Create Pull Request | |
| id: create_pr | |
| uses: peter-evans/create-pull-request@v6 | |
| with: | |
| token: ${{ secrets.GH_PAT }} | |
| base: main | |
| commit-message: | | |
| Update releases.properties | |
| Auto-generated from release ${{ github.event.release.tag_name || github.event.inputs.release_tag }} | |
| branch: update-releases-${{ github.event.release.tag_name || github.event.inputs.release_tag }} | |
| delete-branch: true | |
| title: 'Update releases.properties from release ${{ github.event.release.tag_name || github.event.inputs.release_tag }}' | |
| body: | | |
| ## 🤖 Automated Releases Properties Update | |
| This PR updates the `releases.properties` file with new versions from release `${{ github.event.release.tag_name || github.event.inputs.release_tag }}`. | |
| ### Changes: | |
| - Extracted .7z assets from the release | |
| - Added version entries with download URLs | |
| - Maintained semver ordering (newest first) | |
| **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) }} | |
| ### Next Steps: | |
| 1. ⏳ Link validation will run automatically | |
| 2. ✅ Once validation passes, this PR will auto-merge | |
| 3. ❌ If validation fails, please review and fix invalid URLs | |
| labels: | | |
| automated | |
| releases-update | |
| - name: Wait for validation checks | |
| if: steps.create_pr.outputs.pull-request-number != '' | |
| run: | | |
| echo "Waiting for link validation to complete..." | |
| sleep 10 | |
| - name: Enable auto-merge | |
| if: steps.create_pr.outputs.pull-request-number != '' | |
| run: | | |
| gh pr merge ${{ steps.create_pr.outputs.pull-request-number }} --auto --squash | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_PAT }} |