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
72 changes: 70 additions & 2 deletions .github/workflows/cicd-2-main-branch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ on:
push:
branches:
- main
tags:
- 'v*'
workflow_dispatch:

concurrency:
group: cicd-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read
contents: write
id-token: write
attestations: write
security-events: write
Expand All @@ -26,7 +28,73 @@ jobs:
uses: ./.github/workflows/stage-2-test.yaml
secrets: inherit

build-stage:
release-stage:
needs: test-stage
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
outputs:
new_release_published: ${{ steps.release.outputs.new_release_published }}
new_release_version: ${{ steps.release.outputs.new_release_version }}
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Read tool versions
id: tool-versions
run: |
echo "python=$(awk '/^python / {print $2}' .tool-versions)" >> "$GITHUB_OUTPUT"
echo "uv=$(awk '/^uv / {print $2}' .tool-versions)" >> "$GITHUB_OUTPUT"

- name: Set up Python
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
with:
python-version: ${{ steps.tool-versions.outputs.python }}

- name: Install uv
uses: astral-sh/setup-uv@887a942a15af3a7626099df99e897a18d9e5ab3a # v5.1.0
with:
version: ${{ steps.tool-versions.outputs.uv }}
enable-cache: true

- name: Run semantic-release
id: release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
uv pip install python-semantic-release --system

# Detect next version (--print exits without side effects)
VERSION=$(semantic-release version --print 2>/dev/null) || true

if [[ -n "$VERSION" ]] && ! git ls-remote --tags origin "refs/tags/v$VERSION" | grep -q .; then
echo "Next version detected: $VERSION"

# Create and push the tag (no commit needed, tag push is not blocked by branch protection)
git tag "v$VERSION"
git push origin "v$VERSION"

echo "new_release_published=true" >> "$GITHUB_OUTPUT"
echo "new_release_version=v$VERSION" >> "$GITHUB_OUTPUT"
else
echo "No new release needed (version: ${VERSION:-none}, tag may already exist)"
echo "new_release_published=false" >> "$GITHUB_OUTPUT"
echo "new_release_version=" >> "$GITHUB_OUTPUT"
fi

build-stage:
needs: [test-stage, release-stage]
if: |
always() &&
needs.test-stage.result == 'success' &&
(
github.ref_type == 'tag' ||
needs.release-stage.outputs.new_release_published == 'true'
)
uses: ./.github/workflows/stage-3-build.yaml
with:
version: ${{ needs.release-stage.outputs.new_release_version }}
new_release_published: ${{ needs.release-stage.outputs.new_release_published == 'true' }}
secrets: inherit
32 changes: 32 additions & 0 deletions .github/workflows/codeql.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: "CodeQL Analysis"

on:
pull_request:
branches: [main]
schedule:
- cron: '0 6 * * 1' # Every Monday at 06:00 UTC
workflow_dispatch:

permissions:
contents: read
security-events: write

jobs:
analyze:
name: CodeQL Analysis
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: ['python']
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Initialize CodeQL
uses: github/codeql-action/init@8c78abb9b62512e3c45dea6559ffd924ed8549c8 # v3.28.0
with:
languages: ${{ matrix.language }}

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@8c78abb9b62512e3c45dea6559ffd924ed8549c8 # v3.28.0
20 changes: 0 additions & 20 deletions .github/workflows/stage-1-commit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ on:

permissions:
contents: read
security-events: write

jobs:
scan-secrets:
Expand All @@ -21,22 +20,3 @@ jobs:

- name: Scan secrets
uses: ./.github/actions/scan-secrets

analyze:
name: CodeQL Analysis
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'python' ]
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Initialize CodeQL
uses: github/codeql-action/init@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0
with:
languages: ${{ matrix.language }}

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0
46 changes: 41 additions & 5 deletions .github/workflows/stage-3-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@ name: "Stage 3: Build"

on:
workflow_call:
inputs:
version:
description: "Version to build (overrides detection)"
required: false
type: string
new_release_published:
description: "Whether a new release was published by the release stage"
required: false
type: boolean
default: false

permissions:
contents: read
contents: write
id-token: write
attestations: write

Expand All @@ -15,16 +25,24 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0

- name: Determine version
id: version
run: |
SHORT_HASH="$(git rev-parse --short HEAD)"
echo "short_hash=${SHORT_HASH}" >> "$GITHUB_OUTPUT"
echo "artifact_name=gateway-${SHORT_HASH}.zip" >> "$GITHUB_OUTPUT"
if [[ -n "${{ inputs.version }}" ]]; then
VERSION="${{ inputs.version }}"
elif [[ "${{ github.ref_type }}" == "tag" ]]; then
VERSION="${{ github.ref_name }}"
else
VERSION="$(git rev-parse --short HEAD)"
fi
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "artifact_name=gateway-${VERSION}.zip" >> "$GITHUB_OUTPUT"

- name: Build package
run: ./scripts/bash/package_release.sh "${{ runner.temp }}/dist"
run: ./scripts/bash/package_release.sh "${{ runner.temp }}/dist" "${{ steps.version.outputs.version }}"

- name: Read tool versions
id: tool-versions
Expand Down Expand Up @@ -58,6 +76,24 @@ jobs:
print('All service modules imported successfully')
"

- name: Create or Update Release
if: github.ref_type == 'tag' || inputs.new_release_published
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.version.outputs.version }}
run: |
# Create the release if it doesn't exist. If it does, ignore the error.
gh release create "$VERSION" \
--title "$VERSION" \
--generate-notes \
2>/dev/null || echo "Release already exists, uploading assets..."

# Upload or overwrite assets
gh release upload "$VERSION" \
${{ runner.temp }}/dist/gateway-*.zip \
${{ runner.temp }}/dist/gateway-*.zip.sha256 \
--clobber

- name: Upload artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,16 @@ Run manually:
make githooks-run
```

## Deployment

### Windows Service

The gateway is designed to run as a set of Windows Services on-premises.

- **Deployment Guide**: [docs/deployment/windows-service-deploy.md](docs/deployment/windows-service-deploy.md)
- **Deployment Script**: `scripts/powershell/deploy.ps1`
- **Strategy**: Blue/Green with automatic rollback and health checks.

## Architecture

This gateway implements a lightweight DICOM service architecture:
Expand Down
Loading
Loading