Skip to content

Commit c65dfb0

Browse files
GHA-201 Create action to add release to sonar-update-center-properties (#107)
Co-authored-by: Nils Werner <64034005+nils-werner-sonarsource@users.noreply.github.com>
1 parent b40506f commit c65dfb0

File tree

4 files changed

+185
-0
lines changed

4 files changed

+185
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ A centralized collection of reusable GitHub Actions designed to streamline and a
1919
| [Notify Slack on Failure](notify-slack/README.md) | Sends a Slack notification when a job fails |
2020
| [Publish GitHub Release](publish-github-release/README.md) | Publishes a GitHub Release with notes fetched from Jira or provided directly |
2121
| [Release Jira Version](release-jira-version/README.md) | Releases a Jira version and creates the next one |
22+
| [Sonar Update Center Release](sonar-update-center-release/README.md) | Updates a plugin entry in sonar-update-center-properties and creates a pull request |
2223
| [Update Analyzer](update-analyzer/README.md) | Updates an analyzer version in SonarQube or SonarCloud and creates a pull request |
2324
| [Update Release Ticket Status](update-release-ticket-status/README.md) | Updates the status of a Jira release ticket and can change its assignee |
2425
| [Update Rule Metadata](update-rule-metadata/README.md) | Automates updating rule metadata across all supported languages using the rule-api tooling |
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Sonar Update Center Release Action
2+
3+
This GitHub Action opens a pull request in [sonar-update-center-properties](https://github.com/SonarSource/sonar-update-center-properties) adding a new release section to the specified `.properties` file.
4+
5+
## Prerequisites
6+
7+
Make sure your `release-automation` token in [re-terraform-aws-vault](https://github.com/SonarSource/re-terraform-aws-vault/) allows writing to `sonar-update-center-properties`. It must include:
8+
- `contents: write`
9+
- `pull-requests: write`
10+
11+
## Implementation Details
12+
13+
The action uses a Python script (`update.py`) that performs an in-place update of the `.properties` file.
14+
15+
## Inputs
16+
17+
| Input | Description | Required |
18+
|-----------------|---------------------------------------------------------------------------------------|----------|
19+
| `file` | The `.properties` file to update (e.g., `scannermaven.properties`). | `true` |
20+
| `version` | The new version string (e.g., `5.5.0.6356`). | `true` |
21+
| `description` | Value for the `description` field of the new version entry. | `true` |
22+
| `date` | Value for the `date` field of the new version entry (e.g., `2026-03-04`). Defaults to today's date. | `false` |
23+
| `changelog-url` | Value for the `changelogUrl` field of the new version entry. | `true` |
24+
| `download-url` | Value for the `downloadUrl` field of the new version entry. | `true` |
25+
26+
## Outputs
27+
28+
| Output | Description |
29+
|--------------------|--------------------------------------|
30+
| `pull-request-url` | The URL of the created pull request. |
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: Sonar Update Center Release
2+
description: "For automating updates of files in sonar-update-center-properties"
3+
author: 'SonarSource'
4+
5+
inputs:
6+
file:
7+
description: "File to update, e.g.'scannermaven.properties"
8+
required: true
9+
version:
10+
description: "New version field"
11+
required: true
12+
description:
13+
description: "description field"
14+
required: true
15+
date:
16+
description: "date field in YYYY-MM-DD format, defaults to today"
17+
required: false
18+
changelog-url:
19+
description: "changelogUrl field"
20+
required: true
21+
download-url:
22+
description: "downloadUrl field"
23+
required: true
24+
25+
outputs:
26+
pull-request-url:
27+
description: 'The URL of the created pull request.'
28+
value: ${{ steps.create-pr.outputs.pull-request-url }}
29+
30+
runs:
31+
using: 'composite'
32+
steps:
33+
- name: Get GitHub token from Vault
34+
id: secrets
35+
uses: SonarSource/vault-action-wrapper@v3
36+
with:
37+
secrets: |
38+
development/github/token/{REPO_OWNER_NAME_DASH}-release-automation token | GITHUB_TOKEN;
39+
40+
- name: Checkout target repository
41+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
42+
with:
43+
repository: SonarSource/sonar-update-center-properties
44+
token: ${{ fromJSON(steps.secrets.outputs.vault).GITHUB_TOKEN }}
45+
46+
- name: Set up Python
47+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
48+
with:
49+
python-version: '3.x'
50+
51+
- name: Update File
52+
shell: bash
53+
env:
54+
INPUT_FILE: ${{ inputs.file }}
55+
INPUT_VERSION: ${{ inputs.version }}
56+
INPUT_DESCRIPTION: ${{ inputs.description }}
57+
INPUT_DATE: ${{ inputs.date }}
58+
INPUT_CHANGELOG_URL: ${{ inputs.changelog-url }}
59+
INPUT_DOWNLOAD_URL: ${{ inputs.download-url }}
60+
run: |
61+
set -euo pipefail
62+
DATE="${INPUT_DATE:-$(date +%Y-%m-%d)}"
63+
python "$GITHUB_ACTION_PATH/update.py" \
64+
--file "$INPUT_FILE" \
65+
--version "$INPUT_VERSION" \
66+
--description "$INPUT_DESCRIPTION" \
67+
--date "$DATE" \
68+
--changelogUrl "$INPUT_CHANGELOG_URL" \
69+
--downloadUrl "$INPUT_DOWNLOAD_URL"
70+
71+
- name: Create Pull Request
72+
id: create-pr
73+
# TODO: Switch to our own create-pull-request when it supports other repos.
74+
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0
75+
with:
76+
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
77+
commit-message: Update ${{ inputs.file }} with version ${{ inputs.version }}
78+
title: Update ${{ inputs.file }} with version ${{ inputs.version }}
79+
body: ""
80+
base: "master"
81+
branch: "bot/update-${{ inputs.file }}-${{ inputs.version }}-${{ github.run_id }}"
82+
token: ${{ fromJSON(steps.secrets.outputs.vault).GITHUB_TOKEN }}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import argparse
2+
import sys
3+
4+
# The entire file was written by AI.
5+
6+
PUBLIC_VERSION = 'publicVersions='
7+
8+
9+
def main():
10+
parser = argparse.ArgumentParser(
11+
description='Update a .properties file with a new version entry.'
12+
)
13+
parser.add_argument('--file', required=True, help='Input .properties file')
14+
parser.add_argument('--version', required=True, help='New version string (e.g. 5.5.0.6356)')
15+
parser.add_argument('--description', required=True, help='Release description')
16+
parser.add_argument('--date', required=True, help='Release date (YYYY-MM-DD)')
17+
parser.add_argument('--changelogUrl', required=True, help='Changelog URL')
18+
parser.add_argument('--downloadUrl', required=True, help='Download URL')
19+
args = parser.parse_args()
20+
21+
# First pass: find the current publicVersions value to move it to archivedVersions
22+
old_public_version = None
23+
with open(args.file, 'r') as f:
24+
for line in f:
25+
if line.startswith(PUBLIC_VERSION):
26+
old_public_version = line.rstrip('\n')[len(PUBLIC_VERSION):]
27+
break
28+
29+
if old_public_version is None:
30+
print('ERROR: publicVersions not found in input file', file=sys.stderr)
31+
sys.exit(1)
32+
33+
# Second pass: build the output
34+
with open(args.file, 'r') as f:
35+
lines = f.readlines()
36+
37+
output_lines = []
38+
insert_block_after_next_blank = False
39+
40+
for line in lines:
41+
stripped = line.rstrip('\n')
42+
43+
if stripped.startswith('archivedVersions='):
44+
output_lines.append(f'{stripped},{old_public_version}\n')
45+
continue
46+
47+
if stripped.startswith(PUBLIC_VERSION):
48+
output_lines.append(f'{PUBLIC_VERSION}{args.version}\n')
49+
insert_block_after_next_blank = True
50+
continue
51+
52+
if insert_block_after_next_blank and stripped == '':
53+
output_lines.append(line)
54+
v = args.version
55+
output_lines.append(f'{v}.description={args.description}\n')
56+
output_lines.append(f'{v}.date={args.date}\n')
57+
output_lines.append(f'{v}.changelogUrl={args.changelogUrl}\n')
58+
output_lines.append(f'{v}.downloadUrl={args.downloadUrl}\n')
59+
output_lines.append('\n')
60+
insert_block_after_next_blank = False
61+
continue
62+
63+
output_lines.append(line)
64+
65+
with open(args.file, 'w') as f:
66+
f.writelines(output_lines)
67+
68+
print(f'Written {args.file}', file=sys.stderr)
69+
70+
71+
if __name__ == '__main__':
72+
main()

0 commit comments

Comments
 (0)