GitHub Actions CI/CD Integration

GitHub Actions provides powerful CI/CD workflows that integrate seamlessly with CloudRepo for publishing and consuming artifacts across all supported package types.

This guide covers complete integration patterns for Maven, Gradle, Python (pip, setuptools, Poetry, UV, Pixi), and Clojure projects, along with advanced workflow patterns and security best practices.

Benefits & Overview

Why Use CloudRepo with GitHub Actions

  • Cost Effective: Save 90%+ compared to JFrog Artifactory with no egress fees

  • Native Integration: Works seamlessly with all build tools and package managers

  • Secure: Use GitHub Secrets and environments for credential management

  • Scalable: Handle everything from small libraries to enterprise deployments

  • Support Included: All plans include professional support

Repository URL Format

All CloudRepo repositories follow this URL pattern:

https://[organization-id].mycloudrepo.io/repositories/[repository-id]

Replace [organization-id] and [repository-id] with your actual values throughout this guide.

Setting Up Secrets

GitHub Secrets Configuration

CloudRepo authentication requires username and password credentials stored as GitHub Secrets.

Repository Secrets (for single repository):

  1. Navigate to Settings → Secrets and variables → Actions

  2. Add the following secrets:

    • CLOUDREPO_USERNAME: Your CloudRepo username

    • CLOUDREPO_PASSWORD: Your CloudRepo password

Organization Secrets (for multiple repositories):

  1. Go to Organization Settings → Secrets and variables → Actions

  2. Add the same secrets at organization level

  3. Configure repository access as needed

Using GitHub Environments

For staging and production deployments, use GitHub Environments:

.github/workflows/deploy.yml
name: Deploy to CloudRepo

on:
  push:
    tags:
      - 'v*'

jobs:
  deploy-staging:
    environment: staging
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to Staging
        env:
          CLOUDREPO_URL: ${{ secrets.CLOUDREPO_STAGING_URL }}
          CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
          CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
        run: |
          # Your deployment commands here

  deploy-production:
    needs: deploy-staging
    environment: production
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to Production
        env:
          CLOUDREPO_URL: ${{ secrets.CLOUDREPO_PRODUCTION_URL }}
          CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
          CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
        run: |
          # Your deployment commands here

Maven Workflows

Basic Maven Deployment

Deploy Maven artifacts on every push to main branch:

.github/workflows/maven-deploy.yml
 1name: Maven Deploy
 2
 3on:
 4  push:
 5    branches: [ main ]
 6
 7jobs:
 8  deploy:
 9    runs-on: ubuntu-latest
10
11    steps:
12    - uses: actions/checkout@v4
13
14    - name: Set up JDK 17
15      uses: actions/setup-java@v4
16      with:
17        java-version: '17'
18        distribution: 'temurin'
19        cache: maven
20
21    - name: Configure Maven Settings
22      run: |
23        mkdir -p ~/.m2
24        cat > ~/.m2/settings.xml << 'EOF'
25        <settings>
26          <servers>
27            <server>
28              <id>cloudrepo</id>
29              <username>${env.CLOUDREPO_USERNAME}</username>
30              <password>${env.CLOUDREPO_PASSWORD}</password>
31            </server>
32          </servers>
33        </settings>
34        EOF
35
36    - name: Build and Deploy
37      env:
38        CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
39        CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
40      run: mvn clean deploy

Your pom.xml should include:

pom.xml (distributionManagement section)
<distributionManagement>
  <repository>
    <id>cloudrepo</id>
    <url>https://[organization-id].mycloudrepo.io/repositories/[repository-id]</url>
  </repository>
  <snapshotRepository>
    <id>cloudrepo</id>
    <url>https://[organization-id].mycloudrepo.io/repositories/[snapshot-repository-id]</url>
  </snapshotRepository>
</distributionManagement>

SNAPSHOT vs Release Workflows

Automatically deploy SNAPSHOTs from develop and releases from tags:

.github/workflows/maven-snapshot-release.yml
 1name: Maven Deploy (Snapshot/Release)
 2
 3on:
 4  push:
 5    branches: [ develop, main ]
 6    tags:
 7      - 'v*'
 8
 9jobs:
10  deploy:
11    runs-on: ubuntu-latest
12
13    steps:
14    - uses: actions/checkout@v4
15
16    - name: Set up JDK 17
17      uses: actions/setup-java@v4
18      with:
19        java-version: '17'
20        distribution: 'temurin'
21        cache: maven
22
23    - name: Configure Maven Settings
24      run: |
25        mkdir -p ~/.m2
26        cat > ~/.m2/settings.xml << 'EOF'
27        <settings>
28          <servers>
29            <server>
30              <id>cloudrepo-releases</id>
31              <username>${env.CLOUDREPO_USERNAME}</username>
32              <password>${env.CLOUDREPO_PASSWORD}</password>
33            </server>
34            <server>
35              <id>cloudrepo-snapshots</id>
36              <username>${env.CLOUDREPO_USERNAME}</username>
37              <password>${env.CLOUDREPO_PASSWORD}</password>
38            </server>
39          </servers>
40        </settings>
41        EOF
42
43    - name: Set Version for Release
44      if: startsWith(github.ref, 'refs/tags/v')
45      run: |
46        VERSION=${GITHUB_REF#refs/tags/v}
47        mvn versions:set -DnewVersion=$VERSION
48        mvn versions:commit
49
50    - name: Build and Deploy
51      env:
52        CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
53        CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
54      run: mvn clean deploy
55
56    - name: Create GitHub Release
57      if: startsWith(github.ref, 'refs/tags/v')
58      uses: softprops/action-gh-release@v1
59      with:
60        generate_release_notes: true

Multi-Module Projects

Deploy multi-module Maven projects efficiently:

.github/workflows/maven-multimodule.yml
 1name: Multi-Module Maven Deploy
 2
 3on:
 4  push:
 5    branches: [ main ]
 6
 7jobs:
 8  deploy:
 9    runs-on: ubuntu-latest
10
11    steps:
12    - uses: actions/checkout@v4
13
14    - name: Set up JDK 17
15      uses: actions/setup-java@v4
16      with:
17        java-version: '17'
18        distribution: 'temurin'
19        cache: maven
20
21    - name: Configure Maven Settings
22      run: |
23        mkdir -p ~/.m2
24        cat > ~/.m2/settings.xml << 'EOF'
25        <settings>
26          <servers>
27            <server>
28              <id>cloudrepo</id>
29              <username>${env.CLOUDREPO_USERNAME}</username>
30              <password>${env.CLOUDREPO_PASSWORD}</password>
31            </server>
32          </servers>
33        </settings>
34        EOF
35
36    - name: Build All Modules
37      run: mvn clean install -DskipTests
38
39    - name: Run Tests
40      run: mvn test
41
42    - name: Deploy All Modules
43      env:
44        CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
45        CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
46      run: |
47        # Deploy only changed modules
48        mvn deploy -pl $(git diff --name-only HEAD~1 | grep pom.xml | sed 's|/pom.xml||' | tr '\n' ',')

Gradle Workflows

Basic Gradle Deployment

Deploy Gradle artifacts using the Maven Publish plugin:

.github/workflows/gradle-deploy.yml
 1name: Gradle Deploy
 2
 3on:
 4  push:
 5    branches: [ main ]
 6
 7jobs:
 8  deploy:
 9    runs-on: ubuntu-latest
10
11    steps:
12    - uses: actions/checkout@v4
13
14    - name: Set up JDK 17
15      uses: actions/setup-java@v4
16      with:
17        java-version: '17'
18        distribution: 'temurin'
19
20    - name: Setup Gradle
21      uses: gradle/gradle-build-action@v2
22
23    - name: Build and Publish
24      env:
25        CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
26        CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
27      run: |
28        ./gradlew build publish \
29          -PcloudrepoUsername=$CLOUDREPO_USERNAME \
30          -PcloudrepoPassword=$CLOUDREPO_PASSWORD

Your build.gradle should include:

build.gradle
apply plugin: 'maven-publish'

publishing {
    publications {
        maven(MavenPublication) {
            from components.java

            groupId = 'com.example'
            artifactId = 'my-library'
            version = version
        }
    }

    repositories {
        maven {
            name = 'cloudrepo'
            url = version.endsWith('SNAPSHOT')
                ? 'https://[organization-id].mycloudrepo.io/repositories/[snapshot-repository-id]'
                : 'https://[organization-id].mycloudrepo.io/repositories/[repository-id]'

            credentials {
                username = project.findProperty("cloudrepoUsername") ?: System.getenv("CLOUDREPO_USERNAME")
                password = project.findProperty("cloudrepoPassword") ?: System.getenv("CLOUDREPO_PASSWORD")
            }
        }
    }
}

Gradle with Kotlin DSL

For build.gradle.kts files:

build.gradle.kts
plugins {
    `java-library`
    `maven-publish`
}

publishing {
    publications {
        create<MavenPublication>("maven") {
            from(components["java"])

            groupId = "com.example"
            artifactId = "my-library"
            version = project.version.toString()
        }
    }

    repositories {
        maven {
            name = "cloudrepo"
            url = uri(
                if (version.toString().endsWith("SNAPSHOT")) {
                    "https://[organization-id].mycloudrepo.io/repositories/[snapshot-repository-id]"
                } else {
                    "https://[organization-id].mycloudrepo.io/repositories/[repository-id]"
                }
            )

            credentials {
                username = findProperty("cloudrepoUsername")?.toString()
                    ?: System.getenv("CLOUDREPO_USERNAME")
                password = findProperty("cloudrepoPassword")?.toString()
                    ?: System.getenv("CLOUDREPO_PASSWORD")
            }
        }
    }
}

Python Workflows

Publishing with pip/setuptools

Deploy Python packages using setuptools:

.github/workflows/python-setuptools.yml
 1name: Python Package Deploy (setuptools)
 2
 3on:
 4  push:
 5    tags:
 6      - 'v*'
 7
 8jobs:
 9  deploy:
10    runs-on: ubuntu-latest
11
12    steps:
13    - uses: actions/checkout@v4
14
15    - name: Set up Python
16      uses: actions/setup-python@v4
17      with:
18        python-version: '3.11'
19
20    - name: Install dependencies
21      run: |
22        python -m pip install --upgrade pip
23        pip install build twine
24
25    - name: Build package
26      run: python -m build
27
28    - name: Upload to CloudRepo
29      env:
30        CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
31        CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
32      run: |
33        python -m twine upload \
34          --repository-url https://[organization-id].mycloudrepo.io/repositories/[repository-id] \
35          --username "$CLOUDREPO_USERNAME" \
36          --password "$CLOUDREPO_PASSWORD" \
37          dist/*

Publishing with Poetry

Deploy using Poetry package manager:

.github/workflows/python-poetry.yml
 1name: Python Package Deploy (Poetry)
 2
 3on:
 4  push:
 5    tags:
 6      - 'v*'
 7
 8jobs:
 9  deploy:
10    runs-on: ubuntu-latest
11
12    steps:
13    - uses: actions/checkout@v4
14
15    - name: Set up Python
16      uses: actions/setup-python@v4
17      with:
18        python-version: '3.11'
19
20    - name: Install Poetry
21      uses: snok/install-poetry@v1
22      with:
23        virtualenvs-create: true
24        virtualenvs-in-project: true
25
26    - name: Cache Poetry dependencies
27      uses: actions/cache@v3
28      with:
29        path: .venv
30        key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}
31
32    - name: Install dependencies
33      run: poetry install --no-interaction --no-root
34
35    - name: Build package
36      run: poetry build
37
38    - name: Configure Poetry for CloudRepo
39      env:
40        CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
41        CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
42      run: |
43        poetry config repositories.cloudrepo https://[organization-id].mycloudrepo.io/repositories/[repository-id]
44        poetry config http-basic.cloudrepo "$CLOUDREPO_USERNAME" "$CLOUDREPO_PASSWORD"
45
46    - name: Publish to CloudRepo
47      run: poetry publish -r cloudrepo

Publishing with UV

Deploy Python packages using the UV package manager:

.github/workflows/python-uv.yml
 1name: Python Package Deploy (UV)
 2
 3on:
 4  push:
 5    tags:
 6      - 'v*'
 7
 8jobs:
 9  deploy:
10    runs-on: ubuntu-latest
11
12    steps:
13    - uses: actions/checkout@v4
14
15    - name: Set up Python
16      uses: actions/setup-python@v4
17      with:
18        python-version: '3.11'
19
20    - name: Install UV
21      run: |
22        curl -LsSf https://astral.sh/uv/install.sh | sh
23        echo "$HOME/.cargo/bin" >> $GITHUB_PATH
24
25    - name: Create virtual environment
26      run: uv venv
27
28    - name: Install dependencies
29      run: |
30        source .venv/bin/activate
31        uv pip install build twine
32
33    - name: Build package
34      run: |
35        source .venv/bin/activate
36        python -m build
37
38    - name: Upload to CloudRepo
39      env:
40        CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
41        CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
42      run: |
43        source .venv/bin/activate
44        python -m twine upload \
45          --repository-url https://[organization-id].mycloudrepo.io/repositories/[repository-id] \
46          --username "$CLOUDREPO_USERNAME" \
47          --password "$CLOUDREPO_PASSWORD" \
48          dist/*

Publishing with Pixi

Deploy Python packages managed by Pixi:

.github/workflows/python-pixi.yml
 1name: Python Package Deploy (Pixi)
 2
 3on:
 4  push:
 5    tags:
 6      - 'v*'
 7
 8jobs:
 9  deploy:
10    runs-on: ubuntu-latest
11
12    steps:
13    - uses: actions/checkout@v4
14
15    - name: Install Pixi
16      uses: prefix-dev/setup-pixi@v0.4.1
17      with:
18        pixi-version: latest
19
20    - name: Install project dependencies
21      run: pixi install
22
23    - name: Build package
24      run: pixi run build
25
26    - name: Configure pip index for CloudRepo
27      run: |
28        pixi run pip config set global.index-url https://${{ secrets.CLOUDREPO_USERNAME }}:${{ secrets.CLOUDREPO_PASSWORD }}@[organization-id].mycloudrepo.io/repositories/[repository-id]/simple/
29        pixi run pip config set global.extra-index-url https://pypi.org/simple/
30
31    - name: Upload to CloudRepo
32      env:
33        CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
34        CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
35      run: |
36        pixi run python -m twine upload \
37          --repository-url https://[organization-id].mycloudrepo.io/repositories/[repository-id] \
38          --username "$CLOUDREPO_USERNAME" \
39          --password "$CLOUDREPO_PASSWORD" \
40          dist/*

Clojure Workflows

Publishing with Leiningen

Deploy Clojure libraries using Leiningen:

.github/workflows/clojure-lein.yml
 1name: Clojure Deploy (Leiningen)
 2
 3on:
 4  push:
 5    branches: [ main ]
 6    tags:
 7      - 'v*'
 8
 9jobs:
10  deploy:
11    runs-on: ubuntu-latest
12
13    steps:
14    - uses: actions/checkout@v4
15
16    - name: Set up Java
17      uses: actions/setup-java@v4
18      with:
19        java-version: '17'
20        distribution: 'temurin'
21
22    - name: Install Leiningen
23      run: |
24        curl -O https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein
25        chmod +x lein
26        sudo mv lein /usr/local/bin/
27        lein version
28
29    - name: Configure Leiningen credentials
30      env:
31        CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
32        CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
33      run: |
34        mkdir -p ~/.lein
35        cat > ~/.lein/profiles.clj << EOF
36        {:auth {:repository-auth {#"cloudrepo" {:username "$CLOUDREPO_USERNAME"
37                                                 :password "$CLOUDREPO_PASSWORD"}}}}
38        EOF
39
40    - name: Deploy to CloudRepo
41      run: lein deploy cloudrepo

Your project.clj should include:

project.clj
(defproject com.example/my-library "1.0.0"
  :description "My Clojure Library"
  :dependencies [[org.clojure/clojure "1.11.1"]]

  :repositories [["cloudrepo" {:url "https://[organization-id].mycloudrepo.io/repositories/[repository-id]"
                                :sign-releases false}]]

  :deploy-repositories [["cloudrepo" {:url "https://[organization-id].mycloudrepo.io/repositories/[repository-id]"
                                       :sign-releases false}]])

Publishing with deps.edn and deps-deploy

Deploy Clojure libraries using tools.deps:

.github/workflows/clojure-deps.yml
 1name: Clojure Deploy (deps.edn)
 2
 3on:
 4  push:
 5    tags:
 6      - 'v*'
 7
 8jobs:
 9  deploy:
10    runs-on: ubuntu-latest
11
12    steps:
13    - uses: actions/checkout@v4
14
15    - name: Set up Java
16      uses: actions/setup-java@v4
17      with:
18        java-version: '17'
19        distribution: 'temurin'
20
21    - name: Install Clojure CLI
22      run: |
23        curl -L -O https://github.com/clojure/brew-install/releases/latest/download/linux-install.sh
24        chmod +x linux-install.sh
25        sudo ./linux-install.sh
26
27    - name: Cache Clojure dependencies
28      uses: actions/cache@v3
29      with:
30        path: |
31          ~/.m2/repository
32          ~/.gitlibs
33        key: deps-${{ hashFiles('**/deps.edn') }}
34
35    - name: Build JAR
36      run: clojure -T:build jar
37
38    - name: Deploy to CloudRepo
39      env:
40        CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
41        CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
42      run: |
43        clojure -T:build deploy \
44          :repository cloudrepo \
45          :url '"https://[organization-id].mycloudrepo.io/repositories/[repository-id]"' \
46          :username '"'$CLOUDREPO_USERNAME'"' \
47          :password '"'$CLOUDREPO_PASSWORD'"'

Your build.clj should include:

build.clj
(ns build
  (:require [clojure.tools.build.api :as b]
            [deps-deploy.deps-deploy :as dd]))

(def lib 'com.example/my-library)
(def version (format "1.0.%s" (b/git-count-revs nil)))
(def class-dir "target/classes")
(def jar-file (format "target/%s-%s.jar" (name lib) version))

(defn jar [_]
  (b/delete {:path "target"})
  (b/write-pom {:class-dir class-dir
                :lib lib
                :version version
                :basis (b/create-basis {:project "deps.edn"})
                :src-dirs ["src"]})
  (b/copy-dir {:src-dirs ["src" "resources"]
               :target-dir class-dir})
  (b/jar {:class-dir class-dir
          :jar-file jar-file}))

(defn deploy [{:keys [repository url username password]}]
  (dd/deploy {:installer :remote
              :artifact jar-file
              :pom-file (b/pom-path {:lib lib :class-dir class-dir})
              :repository {repository {:url url
                                       :username username
                                       :password password}}}))

Advanced Workflows

Matrix Builds for Multiple Versions

Test and deploy across multiple language versions:

.github/workflows/matrix-build.yml
 1name: Matrix Build and Deploy
 2
 3on:
 4  push:
 5    branches: [ main ]
 6
 7jobs:
 8  test:
 9    strategy:
10      matrix:
11        java-version: [11, 17, 21]
12        os: [ubuntu-latest, macos-latest, windows-latest]
13
14    runs-on: ${{ matrix.os }}
15
16    steps:
17    - uses: actions/checkout@v4
18
19    - name: Set up JDK ${{ matrix.java-version }}
20      uses: actions/setup-java@v4
21      with:
22        java-version: ${{ matrix.java-version }}
23        distribution: 'temurin'
24        cache: maven
25
26    - name: Run tests
27      run: mvn test
28
29  deploy:
30    needs: test
31    runs-on: ubuntu-latest
32    if: github.ref == 'refs/heads/main'
33
34    steps:
35    - uses: actions/checkout@v4
36
37    - name: Set up JDK 17
38      uses: actions/setup-java@v4
39      with:
40        java-version: '17'
41        distribution: 'temurin'
42        cache: maven
43
44    - name: Configure Maven Settings
45      run: |
46        mkdir -p ~/.m2
47        cat > ~/.m2/settings.xml << 'EOF'
48        <settings>
49          <servers>
50            <server>
51              <id>cloudrepo</id>
52              <username>${env.CLOUDREPO_USERNAME}</username>
53              <password>${env.CLOUDREPO_PASSWORD}</password>
54            </server>
55          </servers>
56        </settings>
57        EOF
58
59    - name: Deploy to CloudRepo
60      env:
61        CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
62        CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
63      run: mvn clean deploy

Conditional Deployment

Deploy based on branch or tag patterns:

.github/workflows/conditional-deploy.yml
 1name: Conditional Deployment
 2
 3on:
 4  push:
 5    branches: [ develop, main ]
 6    tags:
 7      - 'v*'
 8      - 'release-*'
 9
10jobs:
11  deploy:
12    runs-on: ubuntu-latest
13
14    steps:
15    - uses: actions/checkout@v4
16
17    - name: Determine deployment target
18      id: target
19      run: |
20        if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
21          echo "target=production" >> $GITHUB_OUTPUT
22          echo "repo=releases" >> $GITHUB_OUTPUT
23        elif [[ "${{ github.ref }}" == refs/tags/release-* ]]; then
24          echo "target=staging" >> $GITHUB_OUTPUT
25          echo "repo=staging" >> $GITHUB_OUTPUT
26        elif [[ "${{ github.ref }}" == refs/heads/main ]]; then
27          echo "target=staging" >> $GITHUB_OUTPUT
28          echo "repo=staging" >> $GITHUB_OUTPUT
29        else
30          echo "target=development" >> $GITHUB_OUTPUT
31          echo "repo=snapshots" >> $GITHUB_OUTPUT
32        fi
33
34    - name: Set up JDK 17
35      uses: actions/setup-java@v4
36      with:
37        java-version: '17'
38        distribution: 'temurin'
39        cache: maven
40
41    - name: Deploy to ${{ steps.target.outputs.target }}
42      env:
43        CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
44        CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
45        REPO_TYPE: ${{ steps.target.outputs.repo }}
46      run: |
47        echo "Deploying to ${{ steps.target.outputs.target }} environment"
48        mvn clean deploy -P$REPO_TYPE

Caching Dependencies

Optimize build times with intelligent caching:

.github/workflows/cached-deploy.yml
 1name: Cached Deployment
 2
 3on:
 4  push:
 5    branches: [ main ]
 6
 7jobs:
 8  deploy:
 9    runs-on: ubuntu-latest
10
11    steps:
12    - uses: actions/checkout@v4
13
14    - name: Set up JDK 17
15      uses: actions/setup-java@v4
16      with:
17        java-version: '17'
18        distribution: 'temurin'
19
20    - name: Cache Maven dependencies
21      uses: actions/cache@v3
22      with:
23        path: ~/.m2/repository
24        key: maven-${{ runner.os }}-${{ hashFiles('**/pom.xml') }}
25        restore-keys: |
26          maven-${{ runner.os }}-
27
28    - name: Cache Gradle dependencies
29      uses: actions/cache@v3
30      with:
31        path: |
32          ~/.gradle/caches
33          ~/.gradle/wrapper
34        key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
35        restore-keys: |
36          gradle-${{ runner.os }}-
37
38    - name: Cache npm dependencies
39      uses: actions/cache@v3
40      with:
41        path: ~/.npm
42        key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
43        restore-keys: |
44          npm-${{ runner.os }}-
45
46    - name: Build and Deploy
47      env:
48        CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
49        CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
50      run: |
51        # Your build and deploy commands here

Release Automation with Semantic Versioning

Automate releases using conventional commits and semantic versioning:

.github/workflows/semantic-release.yml
 1name: Semantic Release
 2
 3on:
 4  push:
 5    branches: [ main ]
 6
 7jobs:
 8  release:
 9    runs-on: ubuntu-latest
10
11    steps:
12    - uses: actions/checkout@v4
13      with:
14        fetch-depth: 0
15        persist-credentials: false
16
17    - name: Set up Node.js
18      uses: actions/setup-node@v3
19      with:
20        node-version: '18'
21
22    - name: Install semantic-release
23      run: |
24        npm install -g \
25          semantic-release \
26          @semantic-release/changelog \
27          @semantic-release/git \
28          @semantic-release/github \
29          @semantic-release/exec
30
31    - name: Set up JDK 17
32      uses: actions/setup-java@v4
33      with:
34        java-version: '17'
35        distribution: 'temurin'
36        cache: maven
37
38    - name: Configure Maven Settings
39      run: |
40        mkdir -p ~/.m2
41        cat > ~/.m2/settings.xml << 'EOF'
42        <settings>
43          <servers>
44            <server>
45              <id>cloudrepo</id>
46              <username>${env.CLOUDREPO_USERNAME}</username>
47              <password>${env.CLOUDREPO_PASSWORD}</password>
48            </server>
49          </servers>
50        </settings>
51        EOF
52
53    - name: Run semantic-release
54      env:
55        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
56        CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
57        CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
58      run: npx semantic-release

Create a .releaserc.yml configuration:

.releaserc.yml
branches:
  - main

plugins:
  - "@semantic-release/commit-analyzer"
  - "@semantic-release/release-notes-generator"
  - "@semantic-release/changelog"
  - - "@semantic-release/exec"
    - prepareCmd: "mvn versions:set -DnewVersion=${nextRelease.version}"
      publishCmd: "mvn clean deploy"
  - - "@semantic-release/git"
    - assets:
        - "CHANGELOG.md"
        - "pom.xml"
      message: "chore(release): ${nextRelease.version} [skip ci]"
  - "@semantic-release/github"

Security Best Practices

Environment Protection Rules

Configure environment protection for production deployments:

  1. Go to Settings → Environments → production

  2. Add protection rules:

    • Required reviewers

    • Deployment branches (only from main/master)

    • Wait timer before deployment

    • Required status checks

Protected deployment example
jobs:
  deploy-production:
    environment:
      name: production
      url: https://myapp.example.com
    runs-on: ubuntu-latest
    steps:
      # Deployment steps here

Audit Logging

Track all deployments with audit logs:

.github/workflows/audited-deploy.yml
 1name: Audited Deployment
 2
 3on:
 4  push:
 5    tags:
 6      - 'v*'
 7
 8jobs:
 9  deploy:
10    runs-on: ubuntu-latest
11
12    steps:
13    - uses: actions/checkout@v4
14
15    - name: Log deployment start
16      run: |
17        echo "Deployment started by: ${{ github.actor }}"
18        echo "Repository: ${{ github.repository }}"
19        echo "Ref: ${{ github.ref }}"
20        echo "SHA: ${{ github.sha }}"
21        echo "Time: $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
22
23    - name: Deploy to CloudRepo
24      id: deploy
25      env:
26        CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
27        CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
28      run: |
29        # Your deployment commands
30        echo "deploy_status=success" >> $GITHUB_OUTPUT
31
32    - name: Log deployment result
33      if: always()
34      run: |
35        echo "Deployment status: ${{ steps.deploy.outputs.deploy_status || 'failed' }}"
36        echo "Completed at: $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
37
38    - name: Send audit notification
39      if: always()
40      uses: 8398a7/action-slack@v3
41      with:
42        status: ${{ job.status }}
43        text: |
44          Deployment to CloudRepo ${{ job.status }}
45          Actor: ${{ github.actor }}
46          Version: ${{ github.ref_name }}
47        webhook_url: ${{ secrets.SLACK_WEBHOOK }}

Secure Credential Management

Best practices for managing CloudRepo credentials:

  1. Never commit credentials: Always use GitHub Secrets

  2. Rotate credentials regularly: Update secrets periodically

  3. Use least privilege: Create repository-specific users when possible

  4. Enable 2FA: Protect GitHub accounts with two-factor authentication

  5. Review access logs: Regularly audit CloudRepo access logs

Secure credential example
steps:
  - name: Validate secrets are configured
    run: |
      if [ -z "${{ secrets.CLOUDREPO_USERNAME }}" ]; then
        echo "Error: CLOUDREPO_USERNAME secret not configured"
        exit 1
      fi
      if [ -z "${{ secrets.CLOUDREPO_PASSWORD }}" ]; then
        echo "Error: CLOUDREPO_PASSWORD secret not configured"
        exit 1
      fi

  - name: Deploy with masked credentials
    env:
      CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
      CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
    run: |
      # Credentials are automatically masked in logs
      mvn deploy

Troubleshooting

Common Issues and Solutions

Authentication Failures

Error: 401 Unauthorized

Solution: Verify credentials are correctly set in GitHub Secrets:

- name: Test CloudRepo connection
  env:
    CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
    CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
  run: |
    curl -u "$CLOUDREPO_USERNAME:$CLOUDREPO_PASSWORD" \
      https://[organization-id].mycloudrepo.io/repositories/[repository-id]

Deployment Hangs

Solution: Add timeout to deployment steps:

- name: Deploy with timeout
  timeout-minutes: 10
  run: mvn deploy

Artifact Already Exists

Error: 409 Conflict - Artifact already exists

Solution: CloudRepo doesn’t allow overwriting release versions. Options:

  1. Increment version number

  2. Delete existing artifact (if in development)

  3. Use SNAPSHOT versions during development

Network Issues

Solution: Implement retry logic:

- name: Deploy with retry
  uses: nick-invision/retry@v2
  with:
    timeout_minutes: 10
    max_attempts: 3
    retry_wait_seconds: 10
    command: mvn deploy

Build Cache Issues

Solution: Clear caches when experiencing dependency issues:

- name: Clear caches
  run: |
    rm -rf ~/.m2/repository
    rm -rf ~/.gradle/caches

Debug Logging

Enable verbose logging for troubleshooting:

Debug deployment
- name: Deploy with debug logging
  env:
    CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }}
    CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }}
  run: |
    # Maven debug
    mvn deploy -X

    # Gradle debug
    ./gradlew publish --debug

    # Python verbose
    python -m twine upload --verbose dist/*

Getting Help

If you encounter issues not covered here:

  1. Check CloudRepo system status

  2. Review GitHub Actions logs carefully

  3. Contact CloudRepo support at support@cloudrepo.io

  4. Include:

    • Error messages

    • Workflow YAML

    • Build tool configuration

    • CloudRepo repository URL (without credentials)

Additional Resources

For additional examples or integration help, contact the CloudRepo support team at support@cloudrepo.io.