actions / create-release

An Action to create releases via the GitHub Release API
MIT License
1.33k stars 297 forks source link

How to prevent creating multiple releases when using a build matrix? #14

Open nukeop opened 4 years ago

nukeop commented 4 years ago

I have a matrix which results in 3 builds. Is there a way to ensure only the first one will draft a new release?

kf6kjg commented 4 years ago

There does not appear to be. And yes, it's quite annoying to clean up afterwards.

In my case I'm not using a matrix, I'm instead using one job per OS - this is because each OS requires a fair amount of unique operations. I'd still like it to somehow detect that there was a pre-existing release or draft for that tag and name and skip.

However I'm torn between two ways this could be done:

  1. That the behavior be changed to skip the creation if it finds a match for both the given release name AND that exactly one of the release(s) thus found has the same tag. When skipping it should still determine and set the upload_url and any related outputs, thus allowing any downstream steps to proceed normally.
  2. That an option be added, such as allow_duplicates, which if true would behave as it currently does otherwise it would proceed as in the above. I'd rather the default state of this new option be false, but I'd understand if the maintainers would rather it be set true to keep the default behavior unchanged.
nogic1008 commented 4 years ago

Split "Create Release" job and "Build" job, and use upload-artifact and download-artifact to transfer URL.

  release:
    name: Create Github Release
    if: contains(github.ref, 'tags/v')
    needs: [test]
    runs-on: ubuntu-latest
    steps:
    - name: Create Release
      id: create_release
      uses: actions/create-release@v1.0.0
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        tag_name: ${{ github.ref }}
        release_name: Release ${{ github.ref }}
        draft: false
        prerelease: false
    - name: Output Release URL File
      run: echo "${{ steps.create_release.outputs.upload_url }}" > release_url.txt
    - name: Save Release URL File for publish
      uses: actions/upload-artifact@v1
      with:
        name: release_url
        path: release_url.txt

  publish:
    if: contains(github.ref, 'tags/v')
    needs: [test, release]
    runs-on: ubuntu-latest
    strategy:
      matrix:
        version: [foo, bar, baz]
    steps:
    - uses: actions/checkout@v1
    - name: Load Release URL File from release job
      uses: actions/download-artifact@v1
      with:
        name: release_url
    - name: Build
      run: BUILD_COMMAND --version ${{ matrix.version }} --output ./${{ matrix.version }}
        zip -r ${{ matrix.version }} ./${{ matrix.version }}
    - name: Get Release File Name & Upload URL
      id: get_release_info
      run: |
        echo ::set-output name=file_name::${REPOSITORY_NAME##*/}-${TAG_REF_NAME##*/v} # RepositoryName-v1.0.0
        value=`cat release_url/release_url.txt`
        echo ::set-output name=upload_url::$value
      env:
        TAG_REF_NAME: ${{ github.ref }}
        REPOSITORY_NAME: ${{ github.repository }}
    - name: Upload Release Asset
      id: upload-release-asset 
      uses: actions/upload-release-asset@v1.0.1
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        upload_url: ${{ steps.get_release_info.outputs.upload_url }}
        asset_path: ./${{ matrix.rid }}.zip
        asset_name: ${{ steps.get_release_info.outputs.file_name }}-${{ matrix.rid }}.zip
        asset_content_type: application/zip
kf6kjg commented 4 years ago

I prefer to have the release created only if at least one of the builds succeeded. In fact I'd prefer that it only happened if all builds succeeded. But that's my preferred workflow and there might be a way to do it using a split build process like that, but these are workarounds that add additional time and load - but at least there are workarounds. Thank you @nogic1008 for the inspiration.

nathanielatom commented 4 years ago

I have an alternative solution, that runs in a single (defined) job, which has worked well for me. The idea is to use an extra matrix variable on the build you want to upload the release, and use conditionals for any steps that should only get run for an upload.

Code

jobs:
  build:
    name: python ${{ matrix.python }} and ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        python: [3.6, 3.7]
        os: [ubuntu-latest, macOS-latest, windows-latest]
        include: # define single matrix case that performs upload
          - os: ubuntu-latest
            python: 3.7
            upload: true
...
    steps:
...
      - name: build distribution tarball
        if: matrix.upload
        run: echo 42
      - name: create github release
        id: create_release
        if: matrix.upload && github.event_name == 'pull_request' && github.base_ref == 'master'
        uses: actions/create-release@master # @v1 has no body arg
...

References

nathanielatom commented 4 years ago

Another alternative, if you don't have a preference for which matrix build triggers upload, is to skip the matrix include thing and use step conditionals like if: strategy.job-index == 0; although I haven't tested this myself.

https://help.github.com/en/actions/automating-your-workflow-with-github-actions/contexts-and-expression-syntax-for-github-actions#contexts

extrawurst commented 4 years ago

I recently switched to https://github.com/softprops/action-gh-release due to this problem

kmturley commented 4 years ago

One potential approach would be to create:

Then put the create release only in the all.yml

name: All platforms

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Create release
      id: create_release
      uses: actions/create-release@v1
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        tag_name: ${{ github.ref }}
        release_name: Release ${{ github.ref }}

The only problem is that each platform needs the create_release upload url for it's own release:

linux.yml

    - name: Upload release
      id: upload-release-asset 
      uses: actions/upload-release-asset@v1
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        upload_url: ${{ steps.create_release.outputs.upload_url }}
        asset_path: ./build/VST3/artifact/plugin-linux.zip
        asset_name: plugin-linux.zip
        asset_content_type: application/zip

EDIT: found this blog post which is useful: https://dev.to/eugenebabichenko/automated-multi-platform-releases-with-github-actions-1abg

kmturley commented 4 years ago

Another approach is mentioned in this blog post: https://dev.to/eugenebabichenko/automated-multi-platform-releases-with-github-actions-1abg

I got it to work for building a single release containing multiple binaries:

name: Release

on:
  push:
    tags:
      - "v*"

jobs:
  create_release:
    name: Create release
    runs-on: ubuntu-latest
    outputs:
      upload_url: ${{ steps.create_release.outputs.upload_url }}
    steps:
      - name: Create release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: Release ${{ github.ref }}

  build_release:
    name: Build release
    needs: create_release
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        include:
          - os: ubuntu-latest
            zip_name: plugin-linux
            generator: Unix Makefiles
          - os: macos-latest
            zip_name: plugin-mac
            generator: Xcode
          - os: windows-latest
            zip_name: plugin-win
            generator: Visual Studio 16 2019
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Install Linux dependencies
        if: matrix.os == 'ubuntu-latest'
        run: sudo apt-get install cmake gcc "libstdc++6" libx11-xcb-dev libxcb-util-dev libxcb-cursor-dev libxcb-xkb-dev libxkbcommon-dev libxkbcommon-x11-dev libfontconfig1-dev libcairo2-dev libgtkmm-3.0-dev libsqlite3-dev libxcb-keysyms1-dev

      - name: Install macOS dependencies
        if: matrix.os == 'macOS-latest'
        run: brew install cmake

      - name: Install Windows dependencies
        if: matrix.os == 'windows-latest'
        run: |
          choco install cmake --installargs 'ADD_CMAKE_TO_PATH=System'

      - name: Setup
        shell: bash
        run: |
          git submodule update --init --recursive
          cp -R -v ./vst2sdk/public.sdk/source/vst2.x ./vst3sdk/public.sdk/source

      - name: Build
        shell: bash
        run: |
          cmake \
            -G "${{ matrix.generator }}" \
            -DCMAKE_BUILD_TYPE=Release \
            -DSMTG_ADD_VST3_PLUGINS_SAMPLES=ON \
            -DSMTG_ADD_VST3_HOSTING_SAMPLES=OFF \
            -DSMTG_ADD_VSTGUI=ON \
            -DSMTG_MYPLUGINS_SRC_PATH=./src \
            -S ./vst3sdk \
            -B ./build
          cmake --build ./build --config Release

      - name: Compress
        shell: bash
        run: |
          cd ./build/VST3/Release
          mkdir ../artifact
          zip -r ../artifact/${{ matrix.zip_name }}.zip *

      - name: Upload
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ needs.create_release.outputs.upload_url }}
          asset_path: ./build/VST3/artifact/${{ matrix.zip_name }}.zip
          asset_name: ${{ matrix.zip_name }}.zip
          asset_content_type: application/zip
TomasHubelbauer commented 3 years ago

@extrawurst can you show how that Action solves this problem? I wasn't able to figure it out based on their readme. They don't seem to provide an example of use with a build matrix. I am hoping it might be possible to run three OS builds and then create a release only if all three went through and only after they all did. Is this possible with that Action?

extrawurst commented 3 years ago

@TomasHubelbauer no that problem still persists if one of your builds fails the resulting artefact simply is missing