SonarJS currently has two distinct release targets:
| Target | Artifact | Main workflow | Notes |
|---|---|---|---|
| Standard SonarQube analyzer | Maven/JAR release artifacts | .github/workflows/automated-release.yml |
This is the normal SonarJS release flow. |
| SQAA (previously A3S) | Docker image for LanguageAnalyzerService |
.github/workflows/docker-sqaa.yml |
Manual SQAA-only entry point and fallback. |
SQAAis the current name for what older docs and repository names still callA3S.- Some external identifiers still keep the legacy
a3sname for compatibility. The important ones are:- the Docker repository path
a3s/analysis/javascript packages/grpc/src/proto/language_analyzer.protowithoption java_package = "com.sonarsource.a3s.analyzer.grpc";
- the Docker repository path
- Do not rename those compatibility-sensitive identifiers as part of a routine release.
This is the regular SonarJS analyzer release. It produces the standard SonarQube analyzer artifacts and can also automate the SQAA handoff using the same build number.
- Start
.github/workflows/automated-release.yml. - That workflow orchestrates the release and then calls
.github/workflows/release.ymlfor the actual artifact publication. - After the release succeeds,
.github/workflows/bump-versions.ymlopens the next development iteration PR.
The SonarJS workflow is a thin wrapper around SonarSource/release-github-actions/.github/workflows/automated-release.yml@v1 with SonarJS-specific inputs:
- project name
SonarJS - plugin name
javascript - Jira project
JS - optional SQC and SQS integration PRs
- optional SQAA integration, enabled in the SonarJS wrapper and implemented by a custom local workflow
- SLVS, SLVSCODE, SLE, and SLI integration tickets enabled
- the generic
release-github-actionsSQAA integration explicitly disabled, because SonarJS usesanalysis/js_ts_image_taginstead ofgradle/sonar-plugins.versions.toml
The reusable workflow performs the following steps:
- Freeze the target branch.
- Run the releasability checks with
SonarSource/gh-action_releasability@v3. - Resolve the release version with
get-release-version. - Resolve the Jira version with
get-jira-version. - Generate Jira-based release notes with
get-jira-release-notesunless explicit notes were provided. - Create the REL Jira ticket with
create-jira-release-ticket. - Publish the GitHub release with
publish-github-release. - Unfreeze the branch.
- Release the Jira version, create the next Jira version, and move the REL ticket to
Technical Release Done. - Create integration tickets.
- Open analyzer update PRs for SQS and SQC.
After that reusable workflow succeeds, SonarJS runs a custom sqaa_release job that:
- Reuses the released
X.Y.Z.BuildNumberversion from the standard release. - Extracts the Docker tag from the final
.BuildNumbersuffix. - Checks out the release tag
refs/tags/<release-version>so the SQAA image is built from the exact released commit. - Runs the SQAA Docker build and push flow.
- Opens the
sonar-analysis-as-a-servicePR that updatesanalysis/js_ts_image_tag.
The Prepare next development iteration PR waits for this SonarJS-specific SQAA automation to finish, so a failed SQAA handoff blocks the end of the automated release run.
SonarSource/release-github-actions/publish-github-release is the handoff from orchestration to artifact publication:
- It creates or reuses a draft GitHub release for the target version.
- It can attach Repox artifacts to that release if artifact paths were provided.
- It inspects
.github/workflows/release.ymland detects that SonarJS uses thegh-action_releasev7 draft-first flow. - It triggers
.github/workflows/release.ymlwithversion=<release-version>anddryRun=<draft flag>. - It waits for that workflow to finish and fails the orchestration run if the publication workflow fails.
release.yml is the workflow that actually publishes the standard analyzer release artifacts. It calls SonarSource/gh-action_release/.github/workflows/main.yaml@7.4.0 with:
publishToBinaries: truemavenCentralSync: true- the release version
- the dry-run flag
That reusable workflow follows the v7 draft-first release model:
- Create or reuse the draft GitHub release.
- Run releasability checks again inside the publication workflow.
- Load Vault secrets and execute
./gh-action_release/main. - Publish the release artifacts to the standard release targets.
- Sync Maven Central.
- Publish the draft GitHub release.
- Push release telemetry to Datadog.
Because this is a draft-first flow, failures after the draft release exists are normally retried by rerunning the workflow. You do not create a new release version just because one publication attempt failed.
SonarJS does not use the generic release-github-actions version bump action. Instead, after the automated release job finishes, SonarJS runs its own reusable workflow:
- Check out the repository.
- Update the root
pom.xml<revision>to${version}-SNAPSHOT. - Open a PR with
peter-evans/create-pull-request@v8titledPrepare next development iteration.
- Run
.github/workflows/automated-release.yml, usually frommaster. - Monitor the GitHub release publication kicked off through
.github/workflows/release.yml. - Verify the REL ticket and Jira release were updated.
- Verify that the promoted
sonar-javascript-plugin-<version>-cyclonedx.jsonclassifier is present, signed, valid, and containspkg:npmcomponents. - If
sqaa-integrationwas enabled, verify the SQAA Docker image was built from the release tag and that thesonar-analysis-as-a-servicePR was created. - Merge the
Prepare next development iterationPR. - Merge the SQS, SQC, and SQAA integration PRs created by the release automation.
SQAA (previously A3S) can be released in two ways:
- automatically from
.github/workflows/automated-release.yml, reusing the standard release build number and release tag - manually from
.github/workflows/docker-sqaa.ymlfor SQAA-only rebuilds or exceptional reruns
In both cases, the SonarJS side only builds and publishes the Docker image to Repox. The deployment handoff happens afterwards in SonarSource/sonar-analysis-as-a-service.
The SQAA artifact is the Docker image built from the repository root Dockerfile.
Relevant implementation details:
npm run grpc:buildrunsbridge:build:fastand thengrpc:bundlegrpc:bundleproducesbin/grpc-server.cjs- the Docker image copies
bin/and startsnode ./bin/grpc-server.cjs 50051 - the published image tag is the SonarJS build number
Run .github/workflows/docker-sqaa.yml manually when you need an SQAA-only build outside the standard automated release.
This workflow does the following:
- Resolve the Docker tag:
- use the explicit
build-numberinput when provided - otherwise get a SonarJS build number with
SonarSource/ci-github-actions/get-build-number@master
- use the explicit
- Check out the requested branch or tag.
- Install toolchains with
jdx/mise-action@v4.2.0:- Java 21
- Maven 3.9
- Node 24.11.0
- Configure Maven with
SonarSource/ci-github-actions/config-maven@master. - Configure the npm registry for Repox with the Artifactory private-reader token.
- Read Vault secrets:
- Repox QA deployer credentials
- RSPEC GitHub token
- Run
npm ci. - Refresh RSPEC rule data with
npm run rspec:refresh. - Run
npm run grpc:build. - Log in to
repox-sonarsource-docker-builds.jfrog.io. - If
publish-to-release-repois enabled, also log in torepox-sonarsource-docker-releases.jfrog.io. - Build and push the Docker image once, with one or two registry tags depending on
publish-to-release-repo.
For an official release, the resulting command is equivalent to:
docker buildx build --platform linux/arm64 \
--tag "repox-sonarsource-docker-builds.jfrog.io/a3s/analysis/javascript:<build_number>" \
--tag "repox-sonarsource-docker-releases.jfrog.io/a3s/analysis/javascript:<build_number>" \
--push .The image is pushed to:
repox-sonarsource-docker-builds.jfrog.io/a3s/analysis/javascript:<build_number>
When publish-to-release-repo=true, the same tag is also pushed to:
repox-sonarsource-docker-releases.jfrog.io/a3s/analysis/javascript:<build_number>
The two registry entries are two tags for one Docker Buildx result, not two independently built
analyzers. The workflow always adds the builds-registry tag. When
publish-to-release-repo=true, it adds the releases-registry tag to the same docker buildx build
invocation before pushing. Both tags therefore come from the same source ref, build number, and
Docker build.
The registries serve different lifecycle purposes:
| Registry | Purpose |
|---|---|
repox-sonarsource-docker-builds.jfrog.io |
Historical SQAA destination for branch, ad hoc, and staging images. Its artifacts expire after 90 days, so it must not be the source of an official long-lived deployment. |
repox-sonarsource-docker-releases.jfrog.io |
Durable source for images produced from an official SonarJS release tag. sonar-analysis-as-a-service must pull released JSTS versions from here. |
Before durable publication was added, SonarJS published only to the builds registry and
sonar-analysis-as-a-service pulled JSTS from that location. The release workflow initially kept
the builds tag while adding the releases tag so the producer and consumer could be migrated across
repositories without breaking the existing handoff. This makes the dual publication a
compatibility bridge, not a requirement to maintain two independent release artifacts.
The standard automated release sets publish-to-release-repo=true, so it currently publishes both
tags. The manual workflow defaults the input to false, which publishes only to the builds
registry for ordinary branch or ad hoc builds. A manual rerun of an official release must reuse the
original build number and set the input to true so the durable image is restored.
The same qa-deployer credentials intentionally authenticate to both endpoints. Their existing
repox-qa-deployers permissions authorize both pushes; the registry names describe artifact
retention and intended use, not separate Vault identities. Do not introduce a second
docker-release Vault role for this workflow.
Downstream consumers must not rely on the expiring builds copy of an official release. The
SonarJS-to-SQAA handoff passes the numeric tag through analysis/js_ts_image_tag, while
sonar-analysis-as-a-service owns the registry selection and must choose the releases registry.
Once no compatibility consumer needs official tags in the builds registry, the official release
path can be simplified to publish only to the releases registry; branch and ad hoc builds should
continue to use the builds registry.
The a3s repository segment is still intentional legacy naming. Do not change it during a routine SQAA release.
When SQAA automation is enabled in .github/workflows/automated-release.yml:
- The standard release produces a version in the format
X.Y.Z.BuildNumber. - SonarJS reuses that exact
.BuildNumbersuffix for the SQAA Docker tag. - The SQAA image is built from the release tag
refs/tags/<release-version>, not from the moving branch head. - The same Docker tag is published to the durable Repox release registry
repox-sonarsource-docker-releases.jfrog.io. - The same run opens the
sonar-analysis-as-a-servicePR that updatesanalysis/js_ts_image_tag.
This keeps the Java artifacts and the SQAA Docker image on the same released commit and build number.
After the SonarJS workflow succeeds:
- Take the SonarJS build number from the SQAA workflow run.
- Open a PR in
SonarSource/sonar-analysis-as-a-service, or let the automated release create it for you. - Update only
analysis/js_ts_image_tagto that new build number.
Example:
- PR title:
SC-51805 Update JSTS analyzer to 42780 - diff:
analysis/js_ts_image_tagchanged from39440to42780
In SonarSource/sonar-analysis-as-a-service:
.github/workflows/build.ymlreadsanalysis/js_ts_image_tag.- It calls
.github/workflows/pull-and-push-analyzer-image.yml. - That reusable workflow must pull the official release image from the durable release registry:
repox-sonarsource-docker-releases.jfrog.io/a3s/analysis/javascript:${source_tag}
- This pull-source switch is implemented in
SonarSource/sonar-analysis-as-a-service, not in SonarJS. - It then re-tags that image with the
sonar-analysis-as-a-servicebuild number and pushes it to ECR. - The merge to
masteralso triggers.github/workflows/master-deployment.yml, which starts the deployment workflow for the environments.
Do not use the generic SonarSource/release-github-actions/update-analysis-as-a-service action for the SonarJS SQAA release.
That generic action updates gradle/sonar-plugins.versions.toml in sonar-analysis-as-a-service. The current JS/TS SQAA rollout does not use that file. The real SonarJS handoff is the PR that updates analysis/js_ts_image_tag, whether that PR is created automatically or manually.
- For the normal release path, run
.github/workflows/automated-release.ymlwithsqaa-integrationenabled. - For a manual SQAA-only path, run
.github/workflows/docker-sqaa.yml. - Note the SonarJS build number used as the Docker tag.
- If the flow was a manual rerun for an official release, pass the original release build number and enable
publish-to-release-repo. - If the flow was manual, open a PR in
SonarSource/sonar-analysis-as-a-serviceand updateanalysis/js_ts_image_tagto that build number. - Merge the PR to
master. - Let
sonar-analysis-as-a-servicebuild and deployment workflows roll out the new image.