Skip to content

Draft Release

Draft Release #124

Workflow file for this run

# Copyright 2024 The Drasi Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This workflow supports building components with multiple build configurations.
# To add a new build configuration:
# 1. Add a new entry to the BUILD_CONFIGS array below with "name" and "suffix" fields
# 2. The "name" will be passed as BUILD_CONFIG environment variable to the make command
# 3. The Makefiles will append the build config name to the tag (e.g., "tag-azure-linux-amd64")
# 4. Ensure a corresponding Dockerfile exists (e.g., "Dockerfile.azure-linux")
# 5. Both individual platform-specific images and multi-arch manifests will be created for each config
name: Draft Release
on:
workflow_dispatch:
inputs:
tag:
description: 'Version Tag'
required: true
image_prefix:
description: 'Image Prefix'
required: false
default: 'ghcr.io/drasi-project'
permissions:
id-token: write
contents: read
packages: write
# Environment variables with consistent `platforms` fields
env:
RELEASE_PATH: ./release
BUILD_CONFIGS: >-
[
{"name": "default"},
{"name": "azure-linux"}
]
ALL_COMPONENTS: '[
{"label": "Query Host", "path": "query-container/query-host", "name": "query-container-query-host", "platforms": "linux/amd64,linux/arm64", "category": "query"},
{"label": "Publish API", "path": "query-container/publish-api", "name": "query-container-publish-api", "platforms": "linux/amd64,linux/arm64", "category": "query"},
{"label": "View Service", "path": "query-container/view-svc", "name": "query-container-view-svc", "platforms": "linux/amd64,linux/arm64", "category": "query"},
{"label": "Management API", "path": "control-planes/mgmt_api", "name": "api", "platforms": "linux/amd64,linux/arm64", "category": "control-plane"},
{"label": "k8s Resource Provider", "path": "control-planes/kubernetes_provider", "name": "kubernetes-provider", "platforms": "linux/amd64,linux/arm64", "category": "control-plane"},
{"label": "Change Router", "path": "sources/shared/change-router", "name": "source-change-router", "platforms": "linux/amd64,linux/arm64", "category": "sources"},
{"label": "Change Dispatcher", "path": "sources/shared/change-dispatcher", "name": "source-change-dispatcher", "platforms": "linux/amd64,linux/arm64", "category": "sources"},
{"label": "Query API", "path": "sources/shared/query-api", "name": "source-query-api", "platforms": "linux/amd64,linux/arm64", "category": "sources"},
{"label": "Debezium Reactivator", "path": "sources/relational/debezium-reactivator", "name": "source-debezium-reactivator", "platforms": "linux/amd64,linux/arm64", "category": "sources"},
{"label": "SQL Proxy", "path": "sources/relational/sql-proxy", "name": "source-sql-proxy", "platforms": "linux/amd64,linux/arm64", "category": "sources"},
{"label": "CosmosDB Reactivator", "path": "sources/cosmosdb/cosmosdb-ffcf-reactivator", "name": "source-cosmosdb-reactivator", "platforms": "linux/amd64,linux/arm64", "category": "sources"},
{"label": "Gremlin Proxy", "path": "sources/cosmosdb/gremlin-proxy", "name": "source-gremlin-proxy", "platforms": "linux/amd64,linux/arm64", "category": "sources"},
{"label": "Dataverse Reactivator", "path": "sources/dataverse/dataverse-reactivator", "name": "source-dataverse-reactivator", "platforms": "linux/amd64,linux/arm64", "category": "sources"},
{"label": "Dataverse Proxy", "path": "sources/dataverse/dataverse-proxy", "name": "source-dataverse-proxy", "platforms": "linux/amd64,linux/arm64", "category": "sources"},
{"label": "EventHub Reactivator", "path": "sources/eventhub/eventhub-reactivator", "name": "source-eventhub-reactivator", "platforms": "linux/amd64,linux/arm64", "category": "sources"},
{"label": "EventHub Proxy", "path": "sources/eventhub/eventhub-proxy", "name": "source-eventhub-proxy", "platforms": "linux/amd64,linux/arm64", "category": "sources"},
{"label": "Kubernetes Reactivator", "path": "sources/kubernetes/kubernetes-reactivator", "name": "source-kubernetes-reactivator", "platforms": "linux/amd64,linux/arm64", "category": "sources"},
{"label": "Kubernetes Proxy", "path": "sources/kubernetes/kubernetes-proxy", "name": "source-kubernetes-proxy", "platforms": "linux/amd64,linux/arm64", "category": "sources"},
{"label": "SignalR", "path": "reactions/signalr/signalr-reaction", "name": "reaction-signalr", "platforms": "linux/amd64,linux/arm64", "category": "reactions"},
{"label": "Dataverse", "path": "reactions/power-platform/dataverse/dataverse-reaction", "name": "reaction-dataverse", "platforms": "linux/amd64,linux/arm64", "category": "reactions"},
{"label": "Debezium", "path": "reactions/debezium/debezium-reaction", "name": "reaction-debezium", "platforms": "linux/amd64,linux/arm64", "category": "reactions"},
{"label": "Debug", "path": "reactions/platform/debug-reaction", "name": "reaction-debug", "platforms": "linux/amd64,linux/arm64", "category": "reactions"},
{"label": "EventGrid", "path": "reactions/azure/eventgrid-reaction", "name": "reaction-eventgrid", "platforms": "linux/amd64,linux/arm64", "category": "reactions"},
{"label": "EventBridge", "path": "reactions/aws/eventbridge-reaction", "name": "reaction-eventbridge", "platforms": "linux/amd64,linux/arm64", "category": "reactions"},
{"label": "Gremlin", "path": "reactions/gremlin/gremlin-reaction", "name": "reaction-gremlin", "platforms": "linux/amd64,linux/arm64", "category": "reactions"},
{"label": "Result", "path": "reactions/platform/result-reaction", "name": "reaction-result", "platforms": "linux/amd64,linux/arm64", "category": "reactions"},
{"label": "StorageQueue", "path": "reactions/azure/storagequeue-reaction", "name": "reaction-storage-queue", "platforms": "linux/amd64,linux/arm64", "category": "reactions"},
{"label": "SyncDaprStateStore", "path": "reactions/dapr/sync-statestore", "name": "reaction-sync-dapr-statestore", "platforms": "linux/amd64,linux/arm64", "category": "reactions"},
{"label": "PostDaprPubSub", "path": "reactions/dapr/post-pubsub", "name": "reaction-post-dapr-pubsub", "platforms": "linux/amd64,linux/arm64", "category": "reactions"},
{"label": "Http", "path": "reactions/http", "name": "reaction-http", "platforms": "linux/amd64,linux/arm64", "category": "reactions"},
{"label": "StoredProc", "path": "reactions/sql/storedproc-reaction", "name": "reaction-storedproc", "platforms": "linux/amd64,linux/arm64", "category": "reactions"},
{"label": "MCP", "path": "reactions/mcp", "name": "reaction-mcp", "platforms": "linux/amd64,linux/arm64", "category": "reactions"}]'
jobs:
# Setup job to parse and output component JSON
setup:
runs-on: ubuntu-latest
outputs:
all_components: ${{ steps.set_components.outputs.all_components }}
build_configs: ${{ steps.set_components.outputs.build_configs }}
steps:
- name: Set Component Outputs
id: set_components
run: |
echo "all_components=$(echo '${{ env.ALL_COMPONENTS }}' | jq -c .)" >> $GITHUB_OUTPUT
echo "build_configs=$(echo '${{ env.BUILD_CONFIGS }}' | jq -c .)" >> $GITHUB_OUTPUT
- name: Debug Outputs
run: |
echo "All Components: ${{ steps.set_components.outputs.all_components }}"
echo "Build Configs: ${{ steps.set_components.outputs.build_configs }}"
# Validate the branch name
validate:
runs-on: ubuntu-latest
steps:
- name: Validate Branch
run: |
if [[ "${{ github.ref_name }}" =~ ^(release)/ ]]; then
echo "Branch has the correct prefix."
else
echo "Branch does not have the correct prefix. Exiting..."
exit 1
fi
# Build job for all components
build-components:
needs: [validate, setup]
permissions:
packages: write
contents: read
runs-on: ${{ matrix.runner }}
strategy:
matrix:
runner: [ubuntu-latest, ubuntu-24.04-arm]
component: ${{ fromJson(needs.setup.outputs.all_components) }}
build_config: ${{ fromJson(needs.setup.outputs.build_configs) }}
steps:
- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
submodules: true
token: ${{ secrets.DRASI_CORE_PAT }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1
with:
install: true
- name: Log in to GitHub Container Registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Determine platform and tag suffix
id: platform
run: |
# Determine platform suffix
if [[ "${{ matrix.runner }}" == "ubuntu-latest" ]]; then
echo "platform=linux/amd64" >> $GITHUB_OUTPUT
platform_suffix="-amd64"
elif [[ "${{ matrix.runner }}" == "ubuntu-24.04-arm" ]]; then
echo "platform=linux/arm64" >> $GITHUB_OUTPUT
platform_suffix="-arm64"
fi
# The Makefile will handle the build config suffix, we just pass the platform suffix
echo "suffix=${platform_suffix}" >> $GITHUB_OUTPUT
- name: Build and Push to GHCR
if: contains(matrix.component.platforms, steps.platform.outputs.platform)
run: |
cd ${{ matrix.component.path }}
BUILD_CONFIG=${{ matrix.build_config.name }} \
DOCKER_TAG_VERSION=${{ inputs.tag }} \
TAG_SUFFIX=${{ steps.platform.outputs.suffix }} \
IMAGE_PREFIX=${{ inputs.image_prefix }} \
DOCKERX_OPTS="--push --platform ${{ steps.platform.outputs.platform }}" \
make
# Combined manifest creation for all components
create-all-manifests:
needs: build-components
runs-on: ubuntu-latest
steps:
- name: Log in to GitHub Container Registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create and push manifest lists for all components
run: |
# Process all build configs
for build_config in $(echo '${{ env.BUILD_CONFIGS }}' | jq -r '.[].name'); do
echo "Creating manifests for build config: $build_config"
# Track if any components were processed for this build config
build_config_has_images=false
# Process all components for this build config
for component in $(echo '${{ env.ALL_COMPONENTS }}' | jq -r '.[].name'); do
manifests=()
# Get the expected platforms for the component
expected_platforms=$(echo '${{ env.ALL_COMPONENTS }}' | jq -r ".[] | select(.name == \"$component\") | .platforms")
# Check if any images exist for this build config
component_has_images=false
# Calculate the base tag based on Makefile logic
if [ "$build_config" = "default" ]; then
base_tag="${{ inputs.tag }}"
else
base_tag="${{ inputs.tag }}-$build_config"
fi
# Does this component need to be built for linux/amd64?
if echo "$expected_platforms" | grep -q "linux/amd64"; then
amd64_tag="${base_tag}-amd64"
if docker manifest inspect ghcr.io/drasi-project/$component:$amd64_tag > /dev/null 2>&1; then
echo "Found amd64 manifest for $component:$amd64_tag"
manifests+=("ghcr.io/drasi-project/$component:$amd64_tag")
component_has_images=true
else
echo "Warning: amd64 manifest not found for $component:$amd64_tag"
fi
fi
# Does this component need to be built for linux/arm64?
if echo "$expected_platforms" | grep -q "linux/arm64"; then
arm64_tag="${base_tag}-arm64"
if docker manifest inspect ghcr.io/drasi-project/$component:$arm64_tag > /dev/null 2>&1; then
echo "Found arm64 manifest for $component:$arm64_tag"
manifests+=("ghcr.io/drasi-project/$component:$arm64_tag")
component_has_images=true
else
echo "Warning: arm64 manifest not found for $component:$arm64_tag"
fi
fi
# Create the manifest list if there are manifests to combine
if [ ${#manifests[@]} -gt 0 ]; then
final_tag="${base_tag}"
echo "Creating manifest list for $component:$final_tag with ${#manifests[@]} manifests"
docker buildx imagetools create -t ghcr.io/drasi-project/$component:$final_tag ${manifests[@]}
build_config_has_images=true
else
echo "No manifests found for $component with build config $build_config, skipping manifest creation."
fi
done
if [ "$build_config_has_images" = false ]; then
echo "Warning: No images found for build config $build_config. This may indicate the build failed or the Makefiles don't support BUILD_CONFIG=$build_config"
fi
done
build-cli:
runs-on: ubuntu-latest
needs: validate
steps:
- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Set up Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
with:
go-version: '1.21'
- name: Cache Go modules
uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Build
working-directory: cli
run: make VERSION='${{ inputs.tag }}'
- name: Upload artifact
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6
with:
name: cli
path: cli/bin
package-cli:
needs: build-cli
runs-on: ubuntu-latest
name: Publish ${{ matrix.os }}_${{ matrix.arch }} binaries
strategy:
matrix:
include:
- os: linux
arch: arm64
- os: linux
arch: x64
- os: darwin
arch: arm64
- os: darwin
arch: x64
- os: windows
arch: x64
steps:
- name: Download binaries
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: cli
- name: Copy cli binaries to release (non-windows)
if: matrix.os != 'windows'
run: |
mkdir -p ${{ env.RELEASE_PATH}}/cli/${{ matrix.os }}-${{ matrix.arch }}/
cp -r ${{ matrix.os }}-${{ matrix.arch }}/drasi ${{ env.RELEASE_PATH}}/drasi-${{ matrix.os }}-${{ matrix.arch }}
- name: Copy cli binaries to release (windows)
if: matrix.os == 'windows'
run: |
mkdir -p ${{ env.RELEASE_PATH}}/cli/${{ matrix.os }}-${{ matrix.arch }}/
cp -r ${{ matrix.os }}-${{ matrix.arch }}/drasi.exe ${{ env.RELEASE_PATH}}/drasi-${{ matrix.os }}-${{ matrix.arch }}.exe
- name: Upload release
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6
with:
name: drasi_${{ matrix.os }}_${{ matrix.arch }}
path: ${{ env.RELEASE_PATH}}
vscode-extension:
name: Build and publish the VSCode extension
runs-on: ubuntu-latest
needs: validate
steps:
- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Building the extension
run: |
cd dev-tools/vscode/drasi
npm install -g @vscode/vsce
npm install
npm version ${{ inputs.tag }}
vsce package
- name: Copy the extension to release
run: |
mkdir -p ${{ env.RELEASE_PATH}}/vscode-extension/
cp dev-tools/vscode/drasi/drasi-*.vsix ${{ env.RELEASE_PATH}}
- name: Upload release
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6
with:
name: drasi_vscode_extension
path: ${{ env.RELEASE_PATH}}/drasi-*.vsix
# Call image validation workflow
validate-images:
name: Validate Images
needs: create-all-manifests
uses: ./.github/workflows/image-validation.yml
with:
tag: ${{ inputs.tag }}
# Final release job
release:
permissions:
contents: write
packages: read
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
name: Draft Release
needs:
- validate
- create-all-manifests
- validate-images
- package-cli
- vscode-extension
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Download CLI release
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
pattern: drasi_*
merge-multiple: true
path: ${{ env.RELEASE_PATH }}
- name: Download vscode release
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: drasi_vscode_extension
path: ${{ env.RELEASE_PATH }}
- name: Draft Release
run: |
gh release create ${{ inputs.tag }} ${{ env.RELEASE_PATH }}/* --draft --title ${{ inputs.tag }} --target ${{ github.ref_name }} --generate-notes