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
121 changes: 73 additions & 48 deletions .github/workflows/bitween-api-cicd-gateway.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
name: Bitween API CI/CD (Gateway · both)
run-name: Run-${{ github.ref_name }}-${{ github.run_number }}

# Two pipelines that publish nothing under the same name:
# releases/r10.0-develop the simplify9/bitween-develop image and the bitween-develop chart,
# deployed to playground. No NuGet packages, the CLI as a pre-release.
# releases/r10.0 the simplify9/bitween image and the bitween chart clients install
# (ChartMuseum + GHCR), the NuGet packages, the CLI and the SDKs. Never deployed.
# Run workflow by hand on either branch to rerun that branch's pipeline.
on:
push:
branches:
- releases/**
- releases/r10.0
- releases/r10.0-develop
workflow_dispatch:

# One queue for staging AND release, not one per branch. Both jobs below take their patch from
# the same 10.0.x git tags and push the same docker.io/simplify9/bitween:10.0.<patch> image tag,
# and a run only claims its patch when it tags at the very end. Two runs overlapping (a staging
# push, then the staging -> r10.0 merge seconds later) would compute the same patch: the image
# tag is overwritten by whichever finishes last, while ChartMuseum (409 = success) and NuGet
# (--skip-duplicate) silently keep whichever came first.
# One queue per branch. Both pipelines still take their patch from the same 10.0.x git tags, so a
# develop run and a release run that overlap can compute the same patch, but they publish it under
# different names (bitween-develop / bitween, cli-v10.0.N-dev.<run> / cli-v10.0.N, git tag
# 10.0.N-releases-r10-0-develop.<run> / 10.0.N), so nothing is overwritten or silently kept. One
# queue for both would be worse: GitHub keeps a single pending run per group, so a develop push
# would cancel a release waiting behind another develop run.
concurrency:
group: cicd-gateway-bitween-10.0
group: cicd-gateway-bitween-${{ github.ref_name }}
cancel-in-progress: false

# contents: write -> tag job. packages: write -> publish AND pull the Helm chart
Expand All @@ -27,8 +34,8 @@ permissions:

jobs:
build-publish-deploy:
# Staging: build, publish to GHCR only, deploy to playground (or any branch, manually).
if: ${{ (github.event_name == 'push' && github.ref_name == 'releases/r10.0-develop') || github.event_name == 'workflow_dispatch' }}
# Develop: build, publish bitween-develop, deploy to playground.
if: ${{ github.ref_name == 'releases/r10.0-develop' }}
uses: simplify9/.github/.github/workflows/reusable-service-cicd.yml@main
with:
major-version: '10'
Expand All @@ -39,37 +46,31 @@ jobs:
docker-context: '.'
docker-platforms: 'linux/amd64'

chart-name: 'bitween' # must match charts/default Chart.yaml name:
chart-path: './charts/default'

# 1) Publish the Helm chart to GHCR OCI only. ChartMuseum is what clients install from,
# so only the release job below publishes there; staging versions are plain x.y.z and
# would otherwise be the newest chart a client gets.
chart-publish-method: 'github-oci'
# charts/develop is charts/default under its own name (see its Chart.yaml): the reusable
# requires chart-name to match Chart.yaml, and the production chart must stay bitween.
chart-name: 'bitween-develop'
chart-path: './charts/develop'
# ChartMuseum to install it by hand, GHCR for the deploy below.
chart-publish-method: 'both'
chart-repo-url: 'https://charts.sf9.io'

# Docker image stays on Docker Hub
# The chart's image is <image.repo>/<chart name>:<version>, so the image is named after
# the chart. Its own repository also keeps develop off simplify9/bitween:latest.
container-registry: 'docker.io'
image-name: 'simplify9/bitween'
image-name: 'simplify9/bitween-develop'

# Build + unit-test + push the SDK NuGet package (versioned with the
# pipeline semver, e.g. 8.1.x - was 8.0.<run_number> in the old job),
# and the adapter contract package (SimplyWorks.Bitween.Adapters) adapters reference.
nuget-projects: >-
SW.Bitween.Sdk/SW.Bitween.Sdk.csproj
SW.Bitween.Adapters/SW.Bitween.Adapters.csproj
run-tests: 'true'
# Integration tests run against real Postgres/RabbitMQ/MailHog via
# Testcontainers - self-contained, no extra CI services needed, since
# ubuntu-latest already has a Docker daemon available.
test-projects: |
SW.Bitween.UnitTests/SW.Bitween.UnitTests.csproj
SW.Bitween.IntegrationTests/SW.Bitween.IntegrationTests.csproj
# No nuget-projects: develop publishes no packages. The reusable runs the tests only in
# its NuGet job, so develop-tests below runs them.

# 2) Deploy to playground via Gateway API
# Deploy to playground via Gateway API
deploy: true
# 3) Pull the chart from GHCR OCI
# Pull the chart from GHCR OCI
deploy-chart-source: 'github-oci'
deploy-namespace: 'playground'
# Upgrade the existing release in place: with nameOverride=bitween (helm-set-values) every
# resource name and selector is what the bitween chart rendered. A new bitween-develop
# release would run beside the old one, and the older HTTPRoute keeps app-dev.bitween.io.
deploy-release-name: 'bitween'
routing-mode: 'gateway-api'
gateway-hostnames: 'app-dev.bitween.io'
# '/' serves the admin SPA out of this image's wwwroot, so the root has to route
Expand All @@ -85,6 +86,7 @@ jobs:
# kills one mid-traffic, and anything that runs on every replica at once (scheduled jobs, data
# source leases) shows up here first.
helm-set-values: |
nameOverride=bitween
global.environment=Development
replicaCount=2
resources.requests.cpu=25m
Expand All @@ -95,14 +97,12 @@ jobs:
# Docker image push credentials (Docker Hub)
registry-username: ${{ secrets.DOCKERHUB_USERNAME }}
registry-password: ${{ secrets.DOCKERHUB_TOKEN }}
chartmuseum-username: ${{ secrets.CM_USER }}
chartmuseum-password: ${{ secrets.CM_PASSWORD }}

# GHCR chart push + pull and git tagging use the built-in token
github-token: ${{ secrets.GITHUB_TOKEN }}

# NuGet API key for the SDK package push (publishes to nuget.org, the
# reusable's default feed - no nuget-source override needed).
nuget-api-key: ${{ secrets.SWNUGETKEY }}

# Gateway-API cluster kubeconfig (V2)
kubeconfig-gateway: ${{ secrets.S9DEV_KUBECONFIG_V2 }}

Expand All @@ -117,11 +117,33 @@ jobs:
# (openssl rand -base64 48). Changing it signs out everyone holding an older token.
helm-set-secret-values: 'global.token.key=${{ secrets.TokenKey }},db=${{ secrets.dbConnection }},global.bus.rabbitUrl=${{ secrets.rabbitUrl }},global.cloudFiles.secretAccessKey=${{ secrets.SecretAccessKey }},global.cloudFiles.accessKeyId=${{ secrets.AccessKeyId }},global.cloudFiles.serviceUrl=${{ secrets.ServiceUrl }},global.cloudFiles.bucketName=${{ secrets.BucketName }},environmentVariables.Bitween__RabbitMqManagementUrl=${{ secrets.RabbitMqManagementUrl }},environmentVariables.Bitween__RabbitMqManagementPassword=${{ secrets.RabbitMqManagementPassword }},environmentVariables.Bitween__RabbitMqManagementUsername=${{ secrets.RabbitMqManagementUsername }}'

develop-tests:
# The same build and tests the reusable runs in its NuGet job, which develop skips. As before,
# a failure does not hold back the deploy.
if: ${{ github.ref_name == 'releases/r10.0-develop' }}
runs-on: ${{ vars.S9_RUNNER || vars.S9_HOSTED_RUNNER || 'ubuntu-24.04' }}
timeout-minutes: 30
permissions:
contents: read
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: simplify9/.github/.github/actions/dotnet-build@main
with:
projects: '**/*.csproj'
test-projects: |
SW.Bitween.UnitTests/SW.Bitween.UnitTests.csproj
SW.Bitween.IntegrationTests/SW.Bitween.IntegrationTests.csproj
configuration: 'Release'
dotnet-version: '10.0.x'
run-tests: 'true'

publish-release:
# Release: build and publish to ChartMuseum for clients, never deploy. releases/r10.0 is the
# Release: build and publish for clients, never deploy. releases/r10.0 is the
# repository's default branch, so the reusable workflow treats it as a release: a clean
# 10.0.<patch> git tag, and the critical Dependabot gate runs first.
if: ${{ github.event_name == 'push' && github.ref_name == 'releases/r10.0' }}
if: ${{ github.ref_name == 'releases/r10.0' }}
uses: simplify9/.github/.github/workflows/reusable-service-cicd.yml@main
with:
major-version: '10'
Expand All @@ -134,7 +156,9 @@ jobs:

chart-name: 'bitween'
chart-path: './charts/default'
chart-publish-method: 'chartmuseum'
# ChartMuseum, where clients install from today, and GHCR OCI (oci://ghcr.io/simplify9/charts/bitween),
# the same versions as an immutable, digest-pinned mirror.
chart-publish-method: 'both'
chart-repo-url: 'https://charts.sf9.io'

container-registry: 'docker.io'
Expand All @@ -145,6 +169,9 @@ jobs:
SW.Bitween.Sdk/SW.Bitween.Sdk.csproj
SW.Bitween.Adapters/SW.Bitween.Adapters.csproj
run-tests: 'true'
# Integration tests run against real Postgres/RabbitMQ/MailHog via
# Testcontainers - self-contained, no extra CI services needed, since
# ubuntu-latest already has a Docker daemon available.
test-projects: |
SW.Bitween.UnitTests/SW.Bitween.UnitTests.csproj
SW.Bitween.IntegrationTests/SW.Bitween.IntegrationTests.csproj
Expand All @@ -159,12 +186,12 @@ jobs:
nuget-api-key: ${{ secrets.SWNUGETKEY }}
dependabot-alerts-token: ${{ secrets.DEPENDABOT_ALERTS_TOKEN }}

# The bitween CLI and the adapter contract packages carry the version the run above computed, so
# nothing is tagged by hand. A staging build releases the CLI as a pre-release, cli-v<x.y.z>-stg.<run>;
# the release from releases/r10.0 releases it as the latest, cli-v<x.y.z>, and publishes the SDKs.
cli-staging:
# The bitween CLI and the SDKs carry the version the run above computed, so nothing is tagged by
# hand. A develop build releases the CLI as a pre-release, cli-v<x.y.z>-dev.<run>; the release
# from releases/r10.0 releases it as the latest, cli-v<x.y.z>, and publishes the SDKs. Each runs
# only when the job it needs ran, so the branch is decided above.
cli-develop:
needs: build-publish-deploy
if: ${{ github.event_name == 'push' && github.ref_name == 'releases/r10.0-develop' }}
uses: ./.github/workflows/cli-release.yml
with:
version: ${{ needs.build-publish-deploy.outputs.version }}
Expand All @@ -173,14 +200,12 @@ jobs:

cli-release:
needs: publish-release
if: ${{ github.event_name == 'push' && github.ref_name == 'releases/r10.0' }}
uses: ./.github/workflows/cli-release.yml
with:
version: ${{ needs.publish-release.outputs.version }}

sdk-release:
needs: publish-release
if: ${{ github.event_name == 'push' && github.ref_name == 'releases/r10.0' }}
permissions:
contents: read
uses: ./.github/workflows/sdk-release.yml
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/cli-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ name: bitween CLI release
# installed to run them. Never run by hand or by a tag: the CI run that publishes this repository
# calls it with the version it computed (determine-semver: the next patch from the git tags), so the
# CLI carries the version of the release it ships with. The computed version is the bare x.y.z on
# staging too, so a staging build says so with prerelease and passes its run number.
# develop too, so a develop build says so with prerelease and passes its run number.
# a release, 10.0.61 cli-v10.0.61 the latest release
# a prerelease, 10.0.61 with prerelease and run 121 cli-v10.0.61-stg.121 a pre-release, to try out
# Called by bitween-api-cicd-gateway.yml: after the release from releases/r10.0, and after each staging build.
# a prerelease, 10.0.61 with prerelease and run 121 cli-v10.0.61-dev.121 a pre-release, to try out
# Called by bitween-api-cicd-gateway.yml: after the release from releases/r10.0, and after each develop build.
on:
workflow_call:
inputs:
Expand Down Expand Up @@ -43,12 +43,12 @@ jobs:
run: |
v="$VERSION"
if [ "$PRERELEASE" = "true" ]; then
# A pre-release names its run: 10.0.61 from run 121 is 10.0.61-stg.121.
v="${v%%-*}-stg.${RUN_NUMBER:-${GITHUB_RUN_NUMBER}}"
# A pre-release names its run: 10.0.61 from run 121 is 10.0.61-dev.121.
v="${v%%-*}-dev.${RUN_NUMBER:-${GITHUB_RUN_NUMBER}}"
echo "prerelease=true" >> "$GITHUB_OUTPUT"
elif [[ "$v" == *-* ]]; then
# A version that already carries its branch and run: 10.0.61-releases-r10-0-staging.121 is 10.0.61-stg.121.
v="${v%%-*}-stg.${v##*.}"
# A version that already carries its branch and run: 10.0.61-releases-r10-0-develop.121 is 10.0.61-dev.121.
v="${v%%-*}-dev.${v##*.}"
echo "prerelease=true" >> "$GITHUB_OUTPUT"
else
echo "prerelease=false" >> "$GITHUB_OUTPUT"
Expand Down
1 change: 1 addition & 0 deletions charts/develop/.helmignore
9 changes: 9 additions & 0 deletions charts/develop/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# The develop build of charts/default: the same templates and values (symlinked), published as
# bitween-develop so it can never be mistaken for the production bitween chart clients install.
# The image is <image.repo>/<chart name>, so this chart runs simplify9/bitween-develop.
# CI overwrites version and appVersion.
apiVersion: v2
version: 0.0.1
appVersion: 0.0.1
description: A Helm chart for Bitween (develop builds from releases/r10.0-develop)
name: bitween-develop
1 change: 1 addition & 0 deletions charts/develop/README.md
1 change: 1 addition & 0 deletions charts/develop/templates
1 change: 1 addition & 0 deletions charts/develop/values.yaml
4 changes: 2 additions & 2 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ its contract, its Python and Node packages, and publishing through Bitween's API

Each release has a self-contained binary for Linux (x64, arm64, and musl x64 and arm64 for Alpine), macOS (x64, arm64) and
Windows (x64), with a `SHA256SUMS` file. Each release of Bitween from `releases/r10.0` releases the CLI with it, at Bitween's version, as
`cli-v<version>`; each staging build releases a pre-release, `cli-v<version>-stg.<run>`. It needs nothing else
`cli-v<version>`; each build from `releases/r10.0-develop` releases a pre-release, `cli-v<version>-dev.<run>`. It needs nothing else
installed, apart from what the adapters you build need: the .NET SDK for .NET adapters, Python 3.12 or
later for Python ones (with pip when they have requirements), Node 22 or later for JavaScript and
TypeScript ones (with npm when they have dependencies).
Expand All @@ -24,7 +24,7 @@ curl -fsSL https://raw.githubusercontent.com/simplify9/Bitween-api/releases/r10.

That installs the latest release to `~/.local/bin`, after checking the download against `SHA256SUMS`;
`INSTALL_DIR` changes where, and `BITWEEN_CLI_VERSION=10.0.60` picks a version. The script never
picks a staging pre-release on its own, only when named: `BITWEEN_CLI_VERSION=10.0.61-stg.121`. It works on Linux and
picks a develop pre-release on its own, only when named: `BITWEEN_CLI_VERSION=10.0.61-dev.121`. It works on Linux and
macOS, on x64 and arm64, glibc or musl (Alpine). On Windows, download
`bitween-win-x64.zip` from the [releases](https://github.com/simplify9/Bitween-api/releases) and put
`bitween.exe` on your `PATH`.
Expand Down
6 changes: 3 additions & 3 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ Run several replicas behind a load balancer for throughput and availability, and

| Pipeline | Trigger | What it does |
|---|---|---|
| `.github/workflows/bitween-api-cicd-gateway.yml` | Push to `releases/r10.0-staging`, or manual | Runs unit and integration tests, pushes the image to Docker Hub, publishes the chart to GHCR, pushes `SimplyWorks.Bitween.Sdk` and `SimplyWorks.Bitween.Adapters` to NuGet, tags the repository, and deploys the playground environment |
| `.github/workflows/bitween-api-cicd-gateway.yml` | Push to `releases/r10.0` | The same build, tests, image and NuGet packages, with the chart published to `charts.sf9.io` instead. Nothing is deployed. |
| `.github/workflows/cli-release.yml` | Called by the CI/CD workflow, never run by hand or by a tag: after the release from `releases/r10.0`, and after each staging build | Publishes the [bitween CLI](cli.md) at the version that run computed, as self-contained single-file binaries for `linux-x64`, `linux-arm64`, `linux-musl-x64`, `linux-musl-arm64`, `osx-x64`, `osx-arm64` and `win-x64`, with a `SHA256SUMS` file. From the release it is `cli-v<version>`, the latest release; from staging, the pre-release `cli-v<version>-stg.<run>`. `scripts/install-cli.sh` installs the latest release, a pre-release only when named. |
| `.github/workflows/bitween-api-cicd-gateway.yml` | Push to `releases/r10.0-develop`, or manual on it | Runs unit and integration tests, pushes the `simplify9/bitween-develop` image to Docker Hub, publishes the `bitween-develop` chart (`charts/develop`, the default chart under its own name) to `charts.sf9.io` and GHCR, tags the repository, and deploys the playground environment. Publishes no NuGet packages. |
| `.github/workflows/bitween-api-cicd-gateway.yml` | Push to `releases/r10.0`, or manual on it | Runs unit and integration tests, pushes the `simplify9/bitween` image to Docker Hub, publishes the `bitween` chart clients install to `charts.sf9.io` and GHCR (`oci://ghcr.io/simplify9/charts/bitween`), pushes `SimplyWorks.Bitween.Sdk` and `SimplyWorks.Bitween.Adapters` to NuGet, and tags the repository. Nothing is deployed. |
| `.github/workflows/cli-release.yml` | Called by the CI/CD workflow, never run by hand or by a tag: after the release from `releases/r10.0`, and after each develop build | Publishes the [bitween CLI](cli.md) at the version that run computed, as self-contained single-file binaries for `linux-x64`, `linux-arm64`, `linux-musl-x64`, `linux-musl-arm64`, `osx-x64`, `osx-arm64` and `win-x64`, with a `SHA256SUMS` file. From the release it is `cli-v<version>`, the latest release; from develop, the pre-release `cli-v<version>-dev.<run>`. `scripts/install-cli.sh` installs the latest release, a pre-release only when named. |
| `.github/workflows/sdk-release.yml` | Called by the CI/CD workflow after the release from `releases/r10.0` | Publishes the adapter contract packages at Bitween's version: `simplyworks-bitween` to PyPI and `@simplyworks/bitween` to npm, each tested first against SW-Serverless's SDK. Uses the `PYPI_API_TOKEN` and `NPM_TOKEN` secrets; a version already published is left alone. |
| `.github/workflows/dotnet-pr-checks.yml` | Pull requests to `releases/**` | Builds the solution and runs the .NET unit tests |
| `.github/workflows/frontend-tests.yml` | Pull requests to `releases/**` that touch the UI | Runs the UI unit and component tests |
Expand Down
2 changes: 1 addition & 1 deletion scripts/install-cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ case "$arch" in
esac
rid="$os-$arch"

# The newest release; a pre-release (-stg) only when named.
# The newest release; a pre-release (-dev) only when named.
if [ -n "${BITWEEN_CLI_VERSION:-}" ]; then tag="cli-v$BITWEEN_CLI_VERSION"
else tag=$(curl -fsSL "https://api.github.com/repos/$repo/releases" | grep -o '"tag_name": *"cli-v[^"]*"' | sed 's/.*"\(cli-v[^"]*\)"/\1/' | grep -E '^cli-v[0-9.]+$' | head -1); fi
[ -n "$tag" ] || { echo "No bitween CLI release found" >&2; exit 1; }
Expand Down
Loading