Can I make releases public from a private github repo?

The 2022 answer to this question is even more straight-forward. You'd just need to use the pre-installed gh CLI:

gh release create v0.0.1 foobar.zip -R https://github.com/your/repo-here

This command will create a tag v0.0.1 and a release with the local file foobar.zip attached on the public repository. You can run this in the GitHub Action of any private repository.

The -R argument points to the repository you'd like to create a tag/release on. foobar.zip would be located in your local directory.

One thing is important here: GITHUB_TOKEN must still be set as the token of the repository you'd like to release on!

Full example:

- name: Publish
  env:
    GITHUB_TOKEN: "${{ secrets.RELEASE_REPO_SECRET }}"
  run: |
    gh release create v0.0.1 foobar.zip -R https://github.com/your/repo-here

If you're planning to re-release and override existing versions, there is gh release delete as well. The -d flag creates a release as a draft etc. pp. Please take a look at the docs.

I'm using a slightly more advanced approach by setting:

 shell: bash
 run: $GITHUB_ACTION_PATH/scripts/publish.sh

And in file scripts/publish.sh:

#!/usr/bin/env node
const cp = require('child_process')
const fs = require('fs');
const path = require('path');

const APP_VERSION = JSON.parse(fs.readFileSync('package.json', { encoding: 'utf8' })).version
const TAG = `v${APP_VERSION}`

cp.execSync(`gh release create ${TAG} foobar.zip -R https://github.com/your/repo-name`, { stdio: 'inherit' })

This approach enables you to be able to for example, use Node.js or any other programming language available, to extract a version from the project management file of choice (e.g. package.json) and automatically come up with the right tag version and name.


As @VonC mentioned we have to create a second Repository for that. This is not prohibited and i am doing it already. With github workflows i automated this task, I'm using a develop / master branching, so always when I'm pushing anything to the master branch a new version is build and pushed to the public "Realease" Repo.

In my specific use case I'm building an android apk and releasing it via unoffical github api "hub". Some additional advantage of this is you can have an extra issue tracker for foreign issues and bugs.

name: Master CI CD

# using checkout@v2 instead of v1 caus it needs further configuration

on:
  pull_request:
    types: [closed]

jobs:
  UnitTest:
    runs-on: ubuntu-latest
    if: github.event.pull_request.merged
    steps:
      - uses: actions/checkout@v2
      - name: make executable
        run: chmod +x gradlew
      - name: Unit tests
        run: |
          ./gradlew test
  IncrementVersionCode:
    needs: UnitTest
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: set up JDK 1.8
        uses: actions/setup-java@v1
        with:
          java-version: 1.8
      - name: make executable
        run: chmod +x gradlew
      - name: increment version
        run: ./gradlew incrementVersionCode
      - name: Push new version to master
        run: |
          git config --local user.email "[email protected]"
          git config --local user.name "WorkflowBot"
          git commit -m "Increment Build version" -a
          # maybe better amend commits to avoid bot commits
  BuildArtifacts:
    needs: IncrementVersionCode
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: set up JDK 1.8
        uses: actions/setup-java@v1
        with:
          java-version: 1.8
      - name: make executable
        run: chmod +x gradlew
      - name: Build with Gradle
        run: ./gradlew build -x lint

      - name: Rename artifacts
        run: |
          cp app/build/outputs/apk/release/app-release.apk MyApp.apk
      - name: Upload Release
        uses: actions/upload-artifact@master
        with:
          name: Release Apk
          path: MyApp.apk
      - name: Upload Debug
        uses: actions/upload-artifact@master
        with:
          name: Debug Apk
          path: app/build/outputs/apk/debug/app-debug.apk

  # https://dev.to/ychescale9/running-android-emulators-on-ci-from-bitrise-io-to-github-actions-3j76
  E2ETest:
    needs: BuildArtifacts
    runs-on: macos-latest
    strategy:
      matrix:
        api-level: [21, 27]
        arch: [x86]
    steps:
      - name: checkout
        uses: actions/checkout@v2
      - name: Make gradlew executable
        run: chmod +x ./gradlew
      - name: run tests
        uses: reactivecircus/android-emulator-runner@v2
        with:
          api-level: ${{ matrix.api-level }}
          arch: ${{ matrix.arch }}
          script: ./gradlew connectedCheck

  Deploy:
    needs: E2ETest
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/master'
    steps:
      - uses: actions/checkout@v2 # Needed for gradle file to get version information
      - name: Get Hub
        run: |
          curl -fsSL https://github.com/github/hub/raw/master/script/get | bash -s 2.14.1
          cd bin
          chmod +x hub
          cd ..
      - name: Get Apk
        uses: actions/download-artifact@master
        with:
          name: Release Apk
      - name: Publish
        env:
          GITHUB_TOKEN: "${{ secrets.RELEASE_REPO_SECRET }}"
        run: |
          APP_NAME=MyApp
          VERSION_NAME=`grep -oP 'versionName "\K(.*?)(?=")' ./app/build.gradle`
          VERSION_CODE=`cat version.properties | grep "VERSION_CODE" | cut -d'=' -f2`
          FILENAME="${APP_NAME}-v${VERSION_NAME}-${VERSION_CODE}"
          TAG="v${VERSION_NAME}-${VERSION_CODE}"
          TAG="latest-master"
          echo $APP_NAME
          echo $VERSION_NAME
          echo $VERSION_CODE
          echo $FILENAME
          echo $TAG
          git clone https://github.com/MyUser/MyApp-Releases
          cd MyApp-Releases
          ./../bin/hub release delete "${TAG}" || echo "Failed deleting TAG: ${TAG}" # If release got lost catch error with message
          ./../bin/hub release create -a "../${APP_NAME}.apk" -m "Current Master Build: ${FILENAME}" -p "${TAG}"
  EvaluateCode:
    needs: Deploy
    runs-on: ubuntu-latest
    steps:
      - name: Get Hub
        run: |
          echo "TDOO: Run Jacoco for coverage, and other profiling tools"

A workaround would be to create a public repo, composed of:

  • empty commits (git commit --allow-empty)
  • each commit tagged
  • each tag with a release
  • each release with the deliveries (the binaries of your private app)

That way, you have a visible repo dedicated for release hosting, and a private repos for source development.