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):
Navigate to Settings → Secrets and variables → Actions
Add the following secrets:
CLOUDREPO_USERNAME
: Your CloudRepo usernameCLOUDREPO_PASSWORD
: Your CloudRepo password
Organization Secrets (for multiple repositories):
Go to Organization Settings → Secrets and variables → Actions
Add the same secrets at organization level
Configure repository access as needed
Using GitHub Environments
For staging and production deployments, use GitHub Environments:
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:
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:
<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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
(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:
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:
(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:
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:
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:
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:
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:
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:
Go to Settings → Environments → production
Add protection rules:
Required reviewers
Deployment branches (only from main/master)
Wait timer before deployment
Required status checks
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:
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:
Never commit credentials: Always use GitHub Secrets
Rotate credentials regularly: Update secrets periodically
Use least privilege: Create repository-specific users when possible
Enable 2FA: Protect GitHub accounts with two-factor authentication
Review access logs: Regularly audit CloudRepo access logs
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:
Increment version number
Delete existing artifact (if in development)
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:
- 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:
Check CloudRepo system status
Review GitHub Actions logs carefully
Contact CloudRepo support at support@cloudrepo.io
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.