Plugin Release Policy¶
This page defines the release standard for each marketplace that Appcircle publishes CI/CD distribution plug-ins to. It covers versioning, the release trigger, pre-release/beta availability, and prerequisites. It is module-agnostic: it applies to every current and future Appcircle plug-in published to that marketplace, regardless of product line. For the development and testing lifecycle of an individual plug-in, see TDD-0012.
| Marketplace | Ecosystem | Packaging | Host org |
|---|---|---|---|
| RubyGems | Fastlane | RubyGem | appcircleio |
| GitHub Marketplace | GitHub Actions | Node action (committed dist/) |
appcircleio |
| Jenkins Update Center | Jenkins | HPI | jenkinsci |
| Visual Studio Marketplace | Azure DevOps | VSIX | appcircleio |
General principles (all marketplaces)¶
- Version source of truth is the git tag (
vX.Y.Z/X.Y.Z). Tagging is manual. CI never invents a version. - A release must include all intended changes. Publish from the default branch (or a release branch merged into it), never from a partial or feature branch.
- Beta must never shadow production. A normal install resolves the latest stable. Betas require explicit opt-in, on the marketplaces that support them.
- Pre-release testing is mandatory. Exercise the locally built package end-to-end before publishing. See the recipe per marketplace below, and the full lifecycle in TDD-0011.
- Releases run in CI using a stored marketplace credential. Never release from a developer's machine with ad-hoc tokens.
- Self-hosted parity: every plug-in accepts optional
authEndpoint/apiEndpoint, defaulting to the Appcircle cloud (backward compatible). TLS is always verified. Self-signed and private-CA servers require their CA trusted by the runner.
RubyGems (Fastlane)¶
Packaging & version: RubyGem. The version comes from the latest git tag vX.Y.Z. The release script rewrites version.rb at publish time. Tagging is manual.
Release mechanism: a Jenkins Multibranch Pipeline (Jenkinsfile runs pipeline.sh, which runs ci/release.rb), executed inside the repo's Dockerfile.ci image, with the RubyGems API key exposed as the GEM_HOST_API_KEY Jenkins credential. It is branch-gated, so a build publishes at most once.
Standard flow:
- Push
git tag vX.Y.Z(manual). This fixes the version. - Push to
release/x.y.zto publish a pre-releasex.y.z.beta.N.Nauto-increments from the betas already on RubyGems for that base version. - Merge to the default branch to publish the production
x.y.z. This is idempotent and skips if that version is already on RubyGems.
Beta: ✅ supported. RubyGems pre-releases are dotted (x.y.z.beta.N, not npm-style -beta.1) and are hidden unless the consumer opts in (gem install <gem> --pre, or an exact --version). gem install and fastlane add_plugin always resolve the latest stable.
Pre-release test: path-link the locally built gem into a throwaway Fastlane project (gem '<plugin>', path: '...' in the Pluginfile) and run a lane end-to-end before tagging.
GitHub Marketplace (GitHub Actions)¶
Packaging & version: a Node action whose committed dist/ bundle is what consumers run (the action does not build at consume time). The version is the latest stable git tag vX.Y.Z. The developer pushes vX.Y.Z manually, and CI derives beta tags from it.
Release mechanism: a native .github/workflows/release.yml using the built-in GITHUB_TOKEN (no external credential, and free on public repos). It is branch-gated.
Standard flow:
- Rebuild and commit
dist/wheneversrc/changes. The published action runs the committed bundle. - Push
git tag vX.Y.Z(manual) to set the stable version. - Push to
release/*for a pre-release: CI tagsvX.Y.Z-beta.N(autoN) and creates a prerelease GitHub Release. The major alias (vX) is not moved. - Merge to the default branch for production: CI publishes the stable
vX.Y.ZGitHub Release and moves the major aliasvXto it.
Beta: ✅ supported. Pre-releases are published as prerelease GitHub Releases (vX.Y.Z-beta.N). releases/latest stays on the last stable, so consumers only get a beta by pinning that exact tag.
Guards:
- A pre-push tag hook (.githooks/pre-push, enabled per clone via git config core.hooksPath .githooks) rejects tags that are not vX.Y.Z / vX.Y.Z-<pre>.
- release.yml runs a build smoke test but not a byte-for-byte dist check. ncc --source-map embeds the build path, so the bundle is not byte-reproducible across machines. Keeping dist/ fresh is the developer's responsibility (step 1).
Pre-release test: run the locally built bundle before tagging, either with uses: ./ in a throwaway workflow on a branch, or with act locally.
Jenkins Update Center (Jenkins)¶
Jenkins is the most involved marketplace. The plug-in lives under the jenkinsci org (not appcircleio), the release infrastructure is owned by the Jenkins community, and publishing is gated by a one-time onboarding. We contribute code via PRs and trigger releases, but never touch community secrets. The model is the official Continuous Delivery (CD) of Plugins (JEP-229). It is not maven-release-plugin, and not release branches.
Packaging & version: an HPI built with Maven. The version is
pom.xml's${revision}${changelist}. Set<revision>to the targetX.Y.Z(<changelist>stays-SNAPSHOTduring development). The CD tooling produces the release version from${revision}. The git tag is the trigger, not the version source, so keep the tag equal to<revision>.
One-time onboarding (per repo)¶
- Hosting under
jenkinsci: the repo must be transferred or created under thejenkinsciorg via the Jenkins hosting process (a prerequisite for Update Center publishing). - Maintainers in RPU: in
jenkins-infra/repository-permissions-updater, the filepermissions/plugin-<artifactId>.ymllists thedevelopers. The username is the accounts.jenkins.io / Jira username (lowercase), not necessarily the GitHub username. Each maintainer must have: - an accounts.jenkins.io account,
- logged in at least once to Jira (issues.jenkins.io) and Artifactory (repo.jenkins-ci.org),
- 2FA enabled on their GitHub account.
- Add
cd.yaml: commit.github/workflows/cd.yamlto the plugin repo. It delegates to the official reusable workflow:jobs: maven-cd: uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@v1 secrets: MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }} - Enable CD via an RPU PR: open a PR to
repository-permissions-updateraddingcd:\n enabled: trueto the plugin's permissions file (and ensuregithub:points at the correct repo and thedeveloperslist is current). On merge, the RPU bot auto-provisionsMAVEN_USERNAME/MAVEN_TOKENas encrypted GitHub Actions secrets in the plugin repo. Do not create these by hand (MAVEN_TOKENis a real Artifactory token that the bot generates). - The RPU PR runs
ci.jenkins.iovalidation. A common failure isUser name not known to Jira: <user>, which means that maintainer hasn't logged into Jira, or the case is wrong (use the exact lowercase Jira username). Fix and re-push.
Per-release flow (once onboarded)¶
- Land the code on the default branch (
master) via PR (jenkinsci branch protection blocks direct pushes). - Set the version: bump
pom.xml<revision>to the targetX.Y.Z. - Trigger the release.
cd.yamlis triggered byworkflow_dispatch(a maintainer runs it from the Actions tab) and/or apushof a tag (X.Y.Zmatching<revision>).maven-cdbuilds and deploys torepo.jenkins-ci.org(Artifactory). The Jenkins Update Center picks it up within a few hours.
No
release/x.y.zbranches (not idiomatic for Jenkins). The maintainer triggers the public release. Appcircle's internal Jenkins is never involved.
Beta: ❌ none. The Update Center has no RubyGems-style opt-in beta channel (the experimental Update Center is not used).
Pre-release test: build the HPI locally and run it against a test instance. Use mvn hpi:run (dev Jenkins with the plug-in loaded), or mvn package plus Manage Jenkins → Plugins → Advanced → Deploy Plugin, or a JenkinsRule integration test that runs a real job. Never publish a beta to the Update Center.
Visual Studio Marketplace (Azure DevOps)¶
Packaging & version: a VSIX task extension built with tsc. The version comes from the latest git tag X.Y.Z. pipeline.sh derives it (git describe --tags) and injects it into task.json and vss-extension.json before packaging, so the manifests always match the tag. Tagging is manual.
Release mechanism: a Jenkins pipeline runs pipeline.sh, which packages with tfx and publishes the public extension. The publish token is the repo's existing Jenkins credential AzureDevOpsPluginPublishToken (PUBLISH_TOKEN).
Standard flow:
- Push
git tag X.Y.Z(manual). - Merge to
main.pipeline.shinjects the tag version into the manifests and publishes the public extension viatfx extension publish.
Beta: ❌ none. The Visual Studio Marketplace has no RubyGems-style opt-in prerelease channel (versions are plain MAJOR.MINOR.PATCH), so there is no public beta.
Pre-release test: because there is no beta channel, validate before publishing public. Build the .vsix locally (tfx extension create) and install it into a test organization (private or shared extension), then run it in a pipeline. Only promote to the public extension once verified.
Production publishes from the default branch,
main.