GitHub Actions has become the default CI/CD platform for millions of developers. If your code lives on GitHub, running builds, tests, and deployments directly in Actions eliminates the need for external CI services.
But here’s the problem: your builds need to pull dependencies and push artifacts somewhere. Using public registries works for open source, but private projects need private artifact repositories. And if you’ve priced out JFrog Artifactory or Sonatype Nexus for this, you’ve seen how quickly costs escalate when CI/CD pipelines download artifacts hundreds of times per day.
This guide shows you how to integrate CloudRepo with GitHub Actions for Maven, Gradle, and Python builds. You’ll get working examples you can copy into your workflows today.
Why CloudRepo for GitHub Actions
Before diving into configuration, here’s why CloudRepo works well with GitHub Actions:
No egress fees. Every time your workflow runs mvn install or pip install, it downloads artifacts. With consumption-based pricing (like Artifactory), each download costs money. CloudRepo includes unmetered data transfer on all plans. Run 1,000 builds a day if you need to.
Simple authentication. CloudRepo uses standard HTTP basic auth. No special plugins, no complex token management. GitHub Actions secrets work perfectly.
Reliable uptime. Your CI/CD pipeline is only as reliable as its dependencies. CloudRepo’s infrastructure is designed for high availability, so your builds don’t fail because your artifact repository is down.
Tip
Already have artifacts in Artifactory or Nexus? Our migration guides for Artifactory and Nexus walk you through moving everything over.
Prerequisites
Before configuring your workflows, you’ll need:
- A GitHub repository with Actions enabled
- A CloudRepo account with at least one repository created
- Your CloudRepo credentials (username and API token or password)
Setting Up GitHub Secrets
Store your CloudRepo credentials as GitHub secrets. Never hardcode credentials in workflow files.
- Go to your GitHub repository
- Navigate to Settings > Secrets and variables > Actions
- Add these secrets:
CLOUDREPO_USERNAME: Your CloudRepo usernameCLOUDREPO_PASSWORD: Your CloudRepo password or API token
These secrets will be available as environment variables in your workflows.
Maven Builds with GitHub Actions
Maven is the most common use case. Here’s a complete workflow that builds a Java project, runs tests, and deploys artifacts to CloudRepo.
Workflow Configuration
Create .github/workflows/maven-build.yml:
name: Maven Build and Deploy
on: push: branches: [main, develop] pull_request: branches: [main]
jobs: build: runs-on: ubuntu-latest
steps: - uses: actions/checkout@v4
- name: Set up JDK 21 uses: actions/setup-java@v4 with: java-version: '21' distribution: 'temurin' cache: maven
- name: Build and test run: mvn -B verify
- name: Deploy to CloudRepo if: github.ref == 'refs/heads/main' env: CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }} CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }} run: | mvn -B deploy -s .github/settings.xmlMaven Settings File
Create .github/settings.xml in your repository:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd"> <servers> <server> <id>cloudrepo-releases</id> <username>${env.CLOUDREPO_USERNAME}</username> <password>${env.CLOUDREPO_PASSWORD}</password> </server> <server> <id>cloudrepo-snapshots</id> <username>${env.CLOUDREPO_USERNAME}</username> <password>${env.CLOUDREPO_PASSWORD}</password> </server> </servers></settings>POM Configuration
Add distribution management to your pom.xml:
<distributionManagement> <repository> <id>cloudrepo-releases</id> <url>https://your-org.mycloudrepo.io/repositories/maven-releases</url> </repository> <snapshotRepository> <id>cloudrepo-snapshots</id> <url>https://your-org.mycloudrepo.io/repositories/maven-snapshots</url> </snapshotRepository></distributionManagement>Replace your-org with your CloudRepo organization name.
Important
The id elements in your POM must match the id elements in settings.xml. Maven uses these IDs to look up
credentials.
Gradle Builds with GitHub Actions
Gradle configuration follows a similar pattern but uses Gradle’s publishing plugin.
Workflow Configuration
Create .github/workflows/gradle-build.yml:
name: Gradle Build and Deploy
on: push: branches: [main, develop] pull_request: branches: [main]
jobs: build: runs-on: ubuntu-latest
steps: - uses: actions/checkout@v4
- name: Set up JDK 21 uses: actions/setup-java@v4 with: java-version: '21' distribution: 'temurin' cache: gradle
- name: Grant execute permission for gradlew run: chmod +x gradlew
- name: Build and test run: ./gradlew build
- name: Publish to CloudRepo if: github.ref == 'refs/heads/main' env: CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }} CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }} run: ./gradlew publishGradle Build Configuration
Add publishing configuration to your build.gradle.kts:
plugins { `maven-publish`}
publishing { publications { create<MavenPublication>("mavenJava") { from(components["java"]) } } repositories { maven { name = "cloudrepo" url = uri( if (version.toString().endsWith("SNAPSHOT")) "https://your-org.mycloudrepo.io/repositories/maven-snapshots" else "https://your-org.mycloudrepo.io/repositories/maven-releases" ) credentials { username = System.getenv("CLOUDREPO_USERNAME") password = System.getenv("CLOUDREPO_PASSWORD") } } }}Or if you’re using Groovy DSL (build.gradle):
plugins { id 'maven-publish'}
publishing { publications { mavenJava(MavenPublication) { from components.java } } repositories { maven { name = 'cloudrepo' url = version.endsWith('SNAPSHOT') ? 'https://your-org.mycloudrepo.io/repositories/maven-snapshots' : 'https://your-org.mycloudrepo.io/repositories/maven-releases' credentials { username = System.getenv('CLOUDREPO_USERNAME') password = System.getenv('CLOUDREPO_PASSWORD') } } }}Python/Poetry Builds with GitHub Actions
CloudRepo also hosts Python packages. Here’s how to configure Poetry to publish to your private PyPI repository.
Workflow Configuration
Create .github/workflows/python-build.yml:
name: Python Build and Deploy
on: push: branches: [main] tags: - 'v*' pull_request: branches: [main]
jobs: build: runs-on: ubuntu-latest
steps: - uses: actions/checkout@v4
- name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.12'
- name: Install Poetry uses: snok/install-poetry@v1 with: version: 1.8.0 virtualenvs-create: true virtualenvs-in-project: true
- name: Load cached venv id: cached-poetry-dependencies uses: actions/cache@v4 with: path: .venv key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}
- name: Install dependencies if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' run: poetry install --no-interaction --no-root
- name: Install project run: poetry install --no-interaction
- name: Run tests run: poetry run pytest
- name: Build package run: poetry build
- name: Publish to CloudRepo if: startsWith(github.ref, 'refs/tags/v') env: CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }} CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }} run: | poetry config repositories.cloudrepo https://your-org.mycloudrepo.io/repositories/python-releases/ poetry config http-basic.cloudrepo $CLOUDREPO_USERNAME $CLOUDREPO_PASSWORD poetry publish -r cloudrepoInstalling Private Packages
To install packages from your private CloudRepo repository in other projects:
[[tool.poetry.source]]name = "cloudrepo"url = "https://your-org.mycloudrepo.io/repositories/python-releases/simple/"priority = "supplemental"Then in your workflow, configure authentication before installing:
- name: Configure private repository env: CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USERNAME }} CLOUDREPO_PASSWORD: ${{ secrets.CLOUDREPO_PASSWORD }} run: | poetry config http-basic.cloudrepo $CLOUDREPO_USERNAME $CLOUDREPO_PASSWORD poetry installInfo
For more details on Poetry and private Python repositories, see our complete Poetry guide.
CloudRepo vs. Competitors for CI/CD
Here’s why teams choose CloudRepo over alternatives for their GitHub Actions workflows:
| Feature | CloudRepo | JFrog Artifactory | Sonatype Nexus | GitHub Packages |
|---|---|---|---|---|
| Pricing Model | Flat monthly | Consumption-based | Self-hosted or consumption-based | Free tier + overages |
| Egress Fees | None | Yes (varies by plan) | Self-hosted: your infra costs | Free within Actions |
| Maven Support | Full | Full | Full | Full |
| Gradle Support | Full | Full | Full | Full |
| Python Support | Full | Full | Full | Limited |
| Setup Complexity | Low | High | Medium-High | Medium |
| Support Included | Yes | Extra cost | Extra cost | GitHub support |
Info
GitHub Packages data transfer is free when downloading via GitHub Actions using GITHUB_TOKEN. However, storage limits apply (500MB free, then $0.25/GB), and external downloads outside Actions are billed.
Why Flat Pricing Matters for CI/CD
Consumption-based pricing creates unpredictable costs that scale with your success. The more you build, the more you pay.
Consider a team running 100 builds per day, each downloading 500 MB of dependencies:
Daily transfer: 100 builds x 500 MB = 50 GBMonthly transfer: 50 GB x 30 days = 1,500 GBWith JFrog Artifactory Cloud:
- Consumption charges add up quickly at scale
- Plus base subscription fees ($750+/month for Pro X)
- Enterprise support costs extra
With self-hosted Nexus:
- You pay for your own infrastructure (servers, storage, bandwidth)
- Maintenance and upgrade burden on your team
- No direct egress fees to Sonatype, but infrastructure costs scale with usage
With CloudRepo:
- Team plan: $399/month flat
- No egress fees, no surprises
- Support included
CloudRepo’s predictable pricing means you can scale your CI/CD pipelines without worrying about runaway costs.
Best Practices for CI/CD with CloudRepo
Cache Dependencies Aggressively
GitHub Actions caching reduces both build time and repository load:
- uses: actions/setup-java@v4 with: java-version: '21' distribution: 'temurin' cache: maven # Built-in cachingUse Separate Repositories for Snapshots and Releases
Keep development artifacts separate from production releases:
maven-snapshotsfor-SNAPSHOTversionsmaven-releasesfor stable versionspython-releasesfor published packages
This makes it easy to clean up old snapshots without affecting releases.
Rotate Credentials Regularly
Create dedicated CI/CD credentials in CloudRepo and rotate them periodically. Don’t use your personal account for automated builds.
Implement Branch-Based Deployment Logic
Only deploy from specific branches to prevent accidental releases:
- name: Deploy to CloudRepo if: github.ref == 'refs/heads/main' && github.event_name == 'push' run: mvn deployTroubleshooting Common Issues
401 Unauthorized Errors
- Verify secrets are set correctly in GitHub
- Check that secret names match exactly (they’re case-sensitive)
- Ensure your CloudRepo credentials haven’t expired
- Verify the repository URLs are correct
403 Forbidden Errors
- Confirm your CloudRepo user has write access to the repository
- Check if the repository exists (typos in URLs are common)
- Verify you’re using HTTPS, not HTTP
Slow Builds
- Enable dependency caching in your workflow
- Consider using GitHub-hosted larger runners for complex builds
- Check if your repository is in a region close to GitHub’s runners
Next Steps
You now have everything you need to integrate CloudRepo with GitHub Actions for Maven, Gradle, and Python projects.
Ready to simplify your CI/CD artifact management?
Start your free CloudRepo trial - no credit card required. Get your private repositories set up in minutes and connect them to your GitHub Actions workflows today.
Already using Artifactory or Nexus? Our team can help you migrate. Contact us or check out our migration guides:
Have questions about integrating CloudRepo with your CI/CD pipeline? Our support team is here to help - support is included with every CloudRepo plan, not sold as an expensive add-on.