CI/CD Overview
This guide explains how CI/CD pipelines work on the Ybor Platform, including the reusable GitHub Actions and Workflows available to streamline your build process.
What You'll Learn
- How to use p6m-actions in your workflows
- Categories of available actions
- Required secrets and variables
- How to customize or extend the standard workflows
Architecture
The platform provides p6m-actions — individual GitHub Actions that perform specific tasks. They're composable and can be used directly in your workflows.
┌──────────────────────────────────────────────────────────────┐
│ Your Workflow Files │
│ (.github/workflows/build.yml) │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ p6m-actions │
│ (Individual actions for specific tasks) │
│ │
│ setup → build → login → publish → release │
└──────────────────────────────────────────────────────────────┘
Pipeline Stages
Every CI/CD pipeline follows the same general flow, with language-specific actions at each stage:
1. Setup
Configure the language toolchain and build environment. Each language has a setup action that installs the correct runtime, package manager, and dependencies.
2. Registry Login
Authenticate with Artifactory to access private packages and prepare for publishing. This includes both language-specific package registries (PyPI, NuGet, Maven, Cargo) and Docker registries.
3. Build
Compile, test, and package the application. Build actions run linters, execute tests, and produce artifacts ready for publishing.
4. Publish
Push artifacts to registries. Most applications publish Docker images; libraries may also publish packages to language-specific registries.
5. Release
Create semantic version tags and GitHub releases. The cut-tag actions bump versions in the appropriate manifest file (pyproject.toml, .csproj, pom.xml, Cargo.toml, package.json).
6. Deploy
Trigger deployment by updating Kubernetes manifests with the new image digest. The platform-application-manifest-dispatch action handles this for all languages.
Language-Specific Actions
Each language has its own set of actions following the stages above. See the language reference for complete details:
| Language | Guide |
|---|---|
| JavaScript | JavaScript Actions |
| Python | Python Actions |
| .NET | .NET Actions |
| Java | Java Actions |
| Rust | Rust Actions |
Generic actions that work across all languages:
| Action | Description |
|---|---|
docker-buildx-setup | Set up Docker Buildx for multi-platform builds |
docker-repository-login | Log in to Docker registries |
repository-release | Create GitHub releases |
platform-application-manifest-dispatch | Trigger platform manifest updates for deployment |
Required Secrets and Variables
Configure these at the repository or organization level.
These secrets and variables are provisioned by the Ybor platform during onboarding. If builds are failing due to missing credentials, contact your Admin or DevOps team to verify the configuration.
Secrets
| Secret | Description |
|---|---|
ARTIFACTORY_USERNAME | Artifactory service account username |
ARTIFACTORY_IDENTITY_TOKEN | Artifactory identity token for authentication |
UPDATE_MANIFEST_TOKEN | Token for dispatching platform manifest updates |
Variables
| Variable | Description |
|---|---|
ARTIFACTORY_HOSTNAME | Artifactory server hostname (e.g., artifacts.example.com) |
ARTIFACTORY_PROJECT | Project name in Artifactory |
PLATFORM_DISPATCH_URL | URL for platform manifest dispatch endpoint |
Example Workflow Structure
Here's how a typical build workflow composes these actions. This example uses Python, but the structure is the same for all languages—see the Language Reference for language-specific actions.
- Key Steps
- Complete Workflow
jobs:
build:
runs-on: ubuntu-latest
steps:
# 1. Setup toolchain
- uses: p6m-actions/python-uv-setup@v1
# 2. Login to registries
- uses: p6m-actions/python-uv-repository-login@v1
with:
artifactory-hostname: ${{ vars.ARTIFACTORY_HOSTNAME }}
artifactory-project: ${{ vars.ARTIFACTORY_PROJECT }}
artifactory-username: ${{ secrets.ARTIFACTORY_USERNAME }}
artifactory-token: ${{ secrets.ARTIFACTORY_IDENTITY_TOKEN }}
# 3. Build and test (compiles code, runs tests, produces build artifacts)
- uses: p6m-actions/python-uv-build@v1
# 4. Build Docker image and push to registry
# The built artifacts from step 3 are packaged into the container
# The image digest output is used for deployment
- uses: p6m-actions/python-uv-docker-publish@v1
with:
image: ${{ vars.ARTIFACTORY_HOSTNAME }}/${{ vars.ARTIFACTORY_PROJECT }}-docker-local/applications/my-service
platforms: linux/amd64,linux/arm64
name: Build
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
REGISTRY: ${{ vars.ARTIFACTORY_HOSTNAME }}/${{ vars.ARTIFACTORY_PROJECT }}-docker-local
IMAGE_NAME: applications/my-service
jobs:
build:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
digest: ${{ steps.docker.outputs.digest }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python with uv
uses: p6m-actions/python-uv-setup@v1
- name: Configure Artifactory
uses: p6m-actions/python-uv-repository-login@v1
with:
artifactory-hostname: ${{ vars.ARTIFACTORY_HOSTNAME }}
artifactory-project: ${{ vars.ARTIFACTORY_PROJECT }}
artifactory-username: ${{ secrets.ARTIFACTORY_USERNAME }}
artifactory-token: ${{ secrets.ARTIFACTORY_IDENTITY_TOKEN }}
- name: Build and test
uses: p6m-actions/python-uv-build@v1
- name: Get version
id: version
run: echo "version=$(uv run python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
uses: p6m-actions/docker-buildx-setup@v1
- name: Login to Docker registry
uses: p6m-actions/docker-repository-login@v1
with:
registry: ${{ vars.ARTIFACTORY_HOSTNAME }}
username: ${{ secrets.ARTIFACTORY_USERNAME }}
password: ${{ secrets.ARTIFACTORY_IDENTITY_TOKEN }}
- name: Build and push Docker image
id: docker
uses: p6m-actions/python-uv-docker-publish@v1
with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
${{ steps.version.outputs.version }}
latest
platforms: linux/amd64,linux/arm64
# Auto-cut patch version on merge to main
cut-patch:
needs: build
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: p6m-actions/python-uv-cut-tag@v1
with:
bump: patch
# Update dev environment manifest
deploy-dev:
needs: build
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: p6m-actions/platform-application-manifest-dispatch@v1
with:
repository: ${{ github.repository }}
image-name: my-service
directory-name: my-service
environment: dev
digest: ${{ needs.build.outputs.digest }}
update-manifest-token: ${{ secrets.UPDATE_MANIFEST_TOKEN }}
platform-dispatch-url: ${{ vars.PLATFORM_DISPATCH_URL }}
Customization Options
Use Standard Actions Directly
The simplest approach is to use p6m-actions directly in your workflow files. This gives you full control over the pipeline while benefiting from tested, maintained actions.
Fork and Modify
If you need different behavior, fork the action repository and modify it:
- Fork the action from
p6m-actions/<action-name> - Make your changes
- Reference your fork:
uses: your-org/action-name@v1
Build Custom Workflows
For completely custom pipelines, ensure your build produces:
- Container images pushed to your Artifactory Docker registry
- Image digests for immutable deployment references
- Semantic versions following the platform's versioning scheme
- GitHub tags for release tracking (required for staging and production deployments)
The key integration point is the platform-application-manifest-dispatch action, which triggers deployments by updating Kubernetes manifests with your image digest.
Related
- Containerization — Dockerfile patterns for platform-compatible images
- Versioning — Semantic versioning and tag cutting workflows
- Promotion — Environment promotion workflows
- Language Reference — Complete action reference by language