Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion .github/workflows/automated-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ on:
required: false
type: boolean
default: true
sqc-plugins-deployer-integration:
description: "Also create a PR in sonar-plugins-deployer when sqc-integration is true. Disabled by default during the transition period."
required: false
type: boolean
default: false
runner-environment:
description: "Environment where the workflow will run"
required: false
Expand Down Expand Up @@ -750,6 +755,7 @@ jobs:
outputs:
sqs-pull-request-url: ${{ steps.update-sqs.outputs.pull-request-url }}
sqc-pull-request-url: ${{ steps.update-sqc.outputs.pull-request-url }}
plugins-deployer-pull-request-url: ${{ steps.update-plugins-deployer.outputs.pull-request-url }}
steps:
- name: Update analyzer in SQS
id: update-sqs
Expand Down Expand Up @@ -777,6 +783,18 @@ jobs:
draft: ${{ inputs.is-draft-release }}
reviewers: ${{ github.actor }}

- name: Update analyzer in sonar-plugins-deployer
id: update-plugins-deployer
if: ${{ inputs.sqc-integration && inputs.sqc-plugins-deployer-integration }}
uses: SonarSource/release-github-actions/update-plugins-deployer@v1
with:
release-version: ${{ needs.prepare-release.outputs.release-version }}
ticket-key: ${{ needs.create-integration-tickets.outputs.sqc-ticket-key }}
plugin-name: ${{ inputs.plugin-name }}
secret-name: ${{ inputs.release-automation-secret-name || format('sonar-{0}-release-automation', inputs.plugin-name) }}
draft: ${{ inputs.is-draft-release }}
reviewers: ${{ github.actor }}

- name: Summary
if: ${{ inputs.verbose }}
shell: bash
Expand All @@ -788,6 +806,7 @@ jobs:
RELEASE_AUTOMATION_SECRET_NAME: ${{ inputs.release-automation-secret-name }}
SQS_INTEGRATION: ${{ inputs.sqs-integration == true && 'true' || 'false' }}
SQC_INTEGRATION: ${{ inputs.sqc-integration == true && 'true' || 'false' }}
SQC_PLUGINS_DEPLOYER_INTEGRATION: ${{ inputs.sqc-plugins-deployer-integration == true && 'true' || 'false' }}
run: |
echo "## 🔄 Update Analyzers" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
Expand All @@ -799,6 +818,7 @@ jobs:
echo "### Results" >> $GITHUB_STEP_SUMMARY
if [ "$SQS_INTEGRATION" = "true" ]; then echo "- SQS PR: ${{ steps.update-sqs.outputs.pull-request-url }}" >> $GITHUB_STEP_SUMMARY; fi
if [ "$SQC_INTEGRATION" = "true" ]; then echo "- SQC PR: ${{ steps.update-sqc.outputs.pull-request-url }}" >> $GITHUB_STEP_SUMMARY; fi
if [ "$SQC_INTEGRATION" = "true" ] && [ "$SQC_PLUGINS_DEPLOYER_INTEGRATION" = "true" ]; then echo "- Plugins Deployer PR: ${{ steps.update-plugins-deployer.outputs.pull-request-url }}" >> $GITHUB_STEP_SUMMARY; fi

# This step summarizes the results of the entire release process.
# It checks the outcomes of all previous steps and generates a summary indicating whether the release was
Expand Down Expand Up @@ -837,6 +857,7 @@ jobs:
SQC_TICKET_URL: ${{ needs.create-integration-tickets.outputs.sqc-ticket-url || 'not created' }}
SQS_PR_URL: ${{ needs.update-analyzers.outputs.sqs-pull-request-url || 'not created' }}
SQC_PR_URL: ${{ needs.update-analyzers.outputs.sqc-pull-request-url || 'not created' }}
PLUGINS_DEPLOYER_PR_URL: ${{ inputs.sqc-plugins-deployer-integration == true && needs.update-analyzers.outputs.plugins-deployer-pull-request-url || 'not created' }}
BUMP_VERSION_PR_URL: ${{ needs.bump-version.outputs.pull-request-url || 'not created' }}
RESULT_CHECK_RELEASABILITY: ${{ needs.check-releasability.result }}
RESULT_UPDATE_RULE_METADATA: ${{ needs.update-rule-metadata.result }}
Expand Down Expand Up @@ -882,11 +903,12 @@ jobs:
echo " - SQC Integration Ticket: $SQC_TICKET_URL"
echo " - SQS Analyzer PR: $SQS_PR_URL"
echo " - SQC Analyzer PR: $SQC_PR_URL"
echo " - Plugins Deployer PR: $PLUGINS_DEPLOYER_PR_URL"
echo " - Bump Version PR: $BUMP_VERSION_PR_URL"

echo "## Guidance"
if [[ "$ALL_SUCCESS" == "true" ]]; then
echo "- Review and merge the bump version, SQS and SQC PRs."
echo "- Review and merge the bump version, SQS, SQC, and Plugins Deployer PRs."
echo "- Update integration ticket statuses (ensure SQS ticket fix versions are set)."
else
echo "- Check failed jobs for error messages and re-run as needed."
Expand Down
123 changes: 123 additions & 0 deletions .github/workflows/test-update-plugins-deployer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
name: Test Update Plugins Deployer Action

on:
workflow_call:
pull_request:
paths:
- 'update-plugins-deployer/**'
- '.github/workflows/test-update-plugins-deployer.yml'
push:
branches:
- master
- v*
paths:
- 'update-plugins-deployer/**'
- '.github/workflows/test-update-plugins-deployer.yml'
workflow_dispatch:

jobs:
unit-tests:
name: Unit Tests
runs-on: github-ubuntu-latest-s

steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Run shell unit tests
run: bash update-plugins-deployer/test_update_plugins_yaml.sh

action-tests:
name: Action Tests
runs-on: github-ubuntu-latest-s

steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

# --- Ticket validation ---

- name: Test invalid ticket format (SONAR- prefix)
id: test-sonar-ticket
uses: ./update-plugins-deployer
with:
release-version: '1.0.0.1'
ticket-key: 'SONAR-12345'
plugin-name: 'java'
secret-name: 'test-secret'
continue-on-error: true

- name: Verify SONAR- ticket rejected
run: |
if [[ "${{ steps.test-sonar-ticket.outcome }}" == "success" ]]; then
echo "❌ Action should have failed for non-SC- ticket"
exit 1
fi
echo "✅ SONAR- ticket correctly rejected"

- name: Test invalid ticket format (INVALID- prefix)
id: test-invalid-ticket
uses: ./update-plugins-deployer
with:
release-version: '1.0.0.1'
ticket-key: 'INVALID-123'
plugin-name: 'java'
secret-name: 'test-secret'
continue-on-error: true

- name: Verify INVALID- ticket rejected
run: |
if [[ "${{ steps.test-invalid-ticket.outcome }}" == "success" ]]; then
echo "❌ Action should have failed for INVALID- ticket"
exit 1
fi
echo "✅ INVALID- ticket correctly rejected"

# --- plugins.yaml update logic (using test fixture) ---

- name: Test java anchor update
env:
PLUGINS_YAML: update-plugins-deployer/test_plugins.yaml
PLUGIN_NAME: java
RELEASE_VERSION: '0.0.0.11111'
run: |
cp update-plugins-deployer/test_plugins.yaml /tmp/plugins_java.yaml
PLUGINS_YAML=/tmp/plugins_java.yaml bash update-plugins-deployer/update_plugins_yaml.sh
grep "sonar-java: &version-sonar-java 0.0.0.11111" /tmp/plugins_java.yaml || {
echo "❌ sonar-java anchor not updated"; exit 1
}
COUNT=$(grep -c "0\.0\.0\.11111" /tmp/plugins_java.yaml)
[[ "$COUNT" -eq 1 ]] || { echo "❌ Expected 1 occurrence, got $COUNT"; exit 1; }
echo "✅ java anchor updated, alias references untouched"

- name: Test security anchor (frontends share anchor via plugin-name)
run: |
cp update-plugins-deployer/test_plugins.yaml /tmp/plugins_security.yaml
PLUGINS_YAML=/tmp/plugins_security.yaml PLUGIN_NAME=security \
RELEASE_VERSION="0.0.0.22222" bash update-plugins-deployer/update_plugins_yaml.sh
grep "sonar-security: &version-sonar-security 0.0.0.22222" /tmp/plugins_security.yaml || {
echo "❌ sonar-security anchor not updated"; exit 1
}
COUNT=$(grep -c "0\.0\.0\.22222" /tmp/plugins_security.yaml)
[[ "$COUNT" -eq 1 ]] || { echo "❌ Expected 1 occurrence, got $COUNT — aliases modified"; exit 1; }
echo "✅ sonar-security anchor updated once; all frontend aliases inherit it"

- name: Test go-enterprise strips -enterprise suffix
run: |
cp update-plugins-deployer/test_plugins.yaml /tmp/plugins_go.yaml
PLUGINS_YAML=/tmp/plugins_go.yaml PLUGIN_NAME=go-enterprise RELEASE_VERSION="2.0.0.33333" \
bash update-plugins-deployer/update_plugins_yaml.sh
grep "sonar-go: &version-sonar-go 2.0.0.33333" /tmp/plugins_go.yaml || {
echo "❌ sonar-go anchor not updated"; exit 1
}
echo "✅ go-enterprise → sonar-go mapping correct"

- name: Test dotnet-enterprise maps csharp/vbnet to sonar-dotnet
run: |
cp update-plugins-deployer/test_plugins.yaml /tmp/plugins_dotnet.yaml
PLUGINS_YAML=/tmp/plugins_dotnet.yaml PLUGIN_NAME=dotnet-enterprise RELEASE_VERSION="11.0.0.44444" \
bash update-plugins-deployer/update_plugins_yaml.sh
grep "sonar-dotnet: &version-sonar-dotnet 11.0.0.44444" /tmp/plugins_dotnet.yaml || {
echo "❌ sonar-dotnet anchor not updated"; exit 1
}
echo "✅ dotnet-enterprise → sonar-dotnet mapping correct"
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ A centralized collection of reusable GitHub Actions designed to streamline and a
| [Release Jira Version](release-jira-version/README.md) | Releases a Jira version and creates the next one |
| [Sonar Update Center Release](sonar-update-center-release/README.md) | Updates a plugin entry in sonar-update-center-properties and creates a pull request |
| [Update Analyzer](update-analyzer/README.md) | Updates an analyzer version in SonarQube or SonarCloud and creates a pull request |
| [Update Plugins Deployer](update-plugins-deployer/README.md) | Updates a plugin version in sonar-plugins-deployer and creates a pull request |
| [Update Release Ticket Status](update-release-ticket-status/README.md) | Updates the status of a Jira release ticket and can change its assignee |
| [Update Rule Metadata](update-rule-metadata/README.md) | Automates updating rule metadata across all supported languages using the rule-api tooling |

Expand Down
78 changes: 78 additions & 0 deletions update-plugins-deployer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Update Plugins Deployer Action

Updates a plugin version in [sonar-plugins-deployer](https://github.com/SonarSource/sonar-plugins-deployer) by modifying the version anchor in the `versions:` block of `plugins.yaml`, and creates a pull request with the change.

## Description

The action updates analyzer versions by:
1. Validating the ticket key starts with `SC-`
2. Checking out `plugins.yaml` from `sonar-plugins-deployer`
3. Computing the anchor key from `plugin-name` (strips `-enterprise` suffix; maps `csharp`/`vbnet` → `dotnet`)
4. Updating the version anchor in the `versions:` block — all alias references in `plugins:` pick up the new value automatically
5. Creating a pull request with the changes

## Prerequisites

The `secret-name` provided must have `contents: write` and `pull-requests: write` permissions on `SonarSource/sonar-plugins-deployer`. Add `sonar-plugins-deployer` to the repositories list of the `release-automation` secret in `re-terraform-aws-vault`.

## Dependencies

- [SonarSource/vault-action-wrapper@v3](https://github.com/SonarSource/vault-action-wrapper) for secure token retrieval
- [actions/checkout@v4](https://github.com/actions/checkout) for repository checkout
- [SonarSource/release-github-actions/create-pull-request](../create-pull-request) for pull request creation

## Inputs

| Input | Description | Required | Default |
|---|---|---|---|
| `release-version` | The new version to set (e.g. `1.12.0.12345`) | Yes | |
| `ticket-key` | Jira ticket number. Must start with `SC-`. | Yes | |
| `plugin-name` | Plugin language key, used for the anchor lookup, PR title, commit and branch name | Yes | |
| `secret-name` | Vault secret name granting write access to `sonar-plugins-deployer` | Yes | |
| `base-branch` | Base branch for the PR | No | `master` |
| `draft` | Create PR as draft (`true`/`false`) | No | `false` |
| `reviewers` | Comma-separated GitHub usernames to request review from | No | |
| `pull-request-body` | Body of the pull request | No | |

## Outputs

| Output | Description |
|---|---|
| `pull-request-url` | URL of the created pull request |

## Plugin-name to anchor key mapping

| `plugin-name` value | Anchor key in `plugins.yaml` |
|---|---|
| `java` | `sonar-java` |
| `security` | `sonar-security` |
| `go-enterprise` | `sonar-go` |
| `iac-enterprise` | `sonar-iac` |
| `text-enterprise` | `sonar-text` |
| `python-enterprise` | `sonar-python` |
| `dotnet-enterprise` | `sonar-dotnet` |
| `php`, `kotlin`, etc. | `sonar-{plugin-name}` |

General rule: strip `-enterprise` suffix, prepend `sonar-`. Exception: `dotnet-enterprise` maps to `sonar-dotnet` (covers both `csharp-enterprise` and `vbnet-enterprise` via aliases).

## Usage

```yaml
- name: Update PHP analyzer in sonar-plugins-deployer
uses: SonarSource/release-github-actions/update-plugins-deployer@v1
with:
release-version: '3.58.0.16057'
ticket-key: 'SC-67890'
plugin-name: 'php'
secret-name: 'sonar-php-release-automation'
```

```yaml
- name: Update security analyzer (all frontends share the sonar-security anchor)
uses: SonarSource/release-github-actions/update-plugins-deployer@v1
with:
release-version: '11.30.0.46000'
ticket-key: 'SC-12345'
plugin-name: 'security'
secret-name: 'sonar-security-release-automation'
```
96 changes: 96 additions & 0 deletions update-plugins-deployer/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: 'Update Plugins Deployer'
description: 'Updates the version of a specified analyzer in sonar-plugins-deployer and creates a pull request.'
author: 'SonarSource'

inputs:
release-version:
description: 'The new version to set for the analyzer (e.g., 1.12.0.12345).'
required: true
ticket-key:
description: 'The Jira ticket number. Must start with SC-.'
required: true
plugin-name:
description: 'The language key of the plugin to update (e.g., java, security). Used for PR title, commit message, and branch name.'
required: true
secret-name:
description: 'Name of the secret to fetch from the vault that has write access to sonar-plugins-deployer.'
required: true
base-branch:
description: 'The base branch for the pull request.'
required: false
default: 'master'
draft:
description: 'A boolean value to control if the pull request is created as a draft. When true, the commit message is prefixed with [DO NOT MERGE].'
required: false
default: 'false'
reviewers:
description: 'A comma-separated list of GitHub usernames to request a review from.'
required: false
pull-request-body:
description: 'The body of the pull request.'
required: false

outputs:
pull-request-url:
description: 'The URL of the created pull request.'
value: ${{ steps.create_pr.outputs.pull-request-url }}

runs:
using: 'composite'
steps:
- name: Get GitHub token from Vault
id: secrets
uses: SonarSource/vault-action-wrapper@v3
with:
secrets: |
development/github/token/SonarSource-${{ inputs.secret-name}} token | GITHUB_TOKEN;

- name: Validate ticket and set commit prefix
id: setup_env
shell: bash
env:
TICKET_KEY: ${{ inputs.ticket-key }}
DRAFT: ${{ inputs.draft }}
run: |
if [[ "$TICKET_KEY" != SC-* ]]; then
echo "::error::Invalid ticket format '${TICKET_KEY}'. Must start with SC-."
exit 1
fi

if [[ "$DRAFT" == "true" ]]; then
echo "commit-prefix=[DO NOT MERGE]" >> $GITHUB_OUTPUT
else
echo "commit-prefix=$TICKET_KEY" >> $GITHUB_OUTPUT
fi

- name: Checkout sonar-plugins-deployer
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
repository: SonarSource/sonar-plugins-deployer
ref: ${{ inputs.base-branch }}
sparse-checkout: plugins.yaml
sparse-checkout-cone-mode: false
fetch-depth: 0
token: ${{ fromJSON(steps.secrets.outputs.vault).GITHUB_TOKEN }}

- name: Update analyzer version in plugins.yaml
shell: bash
env:
PLUGINS_YAML: plugins.yaml
PLUGIN_NAME: ${{ inputs.plugin-name }}
RELEASE_VERSION: ${{ inputs.release-version }}
run: bash ${{ github.action_path }}/update_plugins_yaml.sh

- name: Create Pull Request
id: create_pr
uses: SonarSource/release-github-actions/create-pull-request@v1
with:
token: ${{ fromJSON(steps.secrets.outputs.vault).GITHUB_TOKEN }}
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
commit-message: '${{ steps.setup_env.outputs.commit-prefix }} Update `${{ inputs.plugin-name }}` plugins to version ${{ inputs.release-version }}'
title: '${{ steps.setup_env.outputs.commit-prefix }} Update `${{ inputs.plugin-name }}` to version ${{ inputs.release-version }}'
body: ${{ inputs.pull-request-body }}
base: ${{ inputs.base-branch }}
branch: '${{ inputs.plugin-name }}/update-analyzer-${{ inputs.release-version }}'
draft: ${{ inputs.draft }}
reviewers: ${{ inputs.reviewers }}
Loading
Loading