Releaser #1895
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # When a tag is push on the repo, this workflow will run to create a release and add some artifact to it. | |
| name: Releaser | |
| on: | |
| pull_request: | |
| paths: | |
| - .github/workflows/releaser.yml | |
| push: | |
| tags: | |
| - v[0-9]+.[0-9]+.[0-9]+* | |
| - nightly | |
| schedule: | |
| - cron: 30 22 * * * # At 22:30 | |
| workflow_dispatch: {} | |
| permissions: | |
| contents: write | |
| # We set `concurrency` to prevent having this workflow being more than once for the same tag. | |
| concurrency: | |
| group: releaser-${{ github.workflow }}-${{ github.ref_name }} | |
| cancel-in-progress: true | |
| env: | |
| NIGHTLY_RELEASE: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.ref == 'refs/tags/nightly') && 'true' || 'false' }} | |
| jobs: | |
| scheduled-nightly-build: | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| uses: ./.github/workflows/_releaser_nightly_build.yml | |
| version: | |
| needs: scheduled-nightly-build | |
| # Always run the job if `scheduled-nightly-build` job is skipped otherwise only if `scheduled-nightly-build` job was successful. | |
| if: (github.event_name != 'schedule' && github.event_name != 'workflow_dispatch') && always() || success() | |
| uses: ./.github/workflows/_parse_version.yml | |
| with: | |
| version: >- | |
| ${{ | |
| ((github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && needs.scheduled-nightly-build.outputs.version_full) || | |
| (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && github.ref_name != 'nightly' && github.ref_name) || | |
| '' | |
| }} | |
| commit_sha: ${{ needs.scheduled-nightly-build.outputs.commit_sha || github.sha }} | |
| package-parsec-server: | |
| needs: version | |
| if: needs.version.result == 'success' && always() | |
| uses: ./.github/workflows/package-server.yml | |
| with: | |
| version: ${{ needs.version.outputs.full }} | |
| version_patch_run_id: ${{ github.run_id }} | |
| commit_sha: ${{ needs.version.outputs.commit_sha }} | |
| package-parsec-webapp: | |
| needs: version | |
| # Do not run this job if the event is a pull request from dependabot. | |
| if: needs.version.result == 'success' && !(github.event_name == 'pull_request' && github.actor == 'dependabot[bot]') && always() | |
| uses: ./.github/workflows/package-webapp.yml | |
| with: | |
| version: ${{ needs.version.outputs.full }} | |
| version_patch_run_id: ${{ github.run_id }} | |
| commit_sha: ${{ needs.version.outputs.commit_sha }} | |
| nightly_build: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.ref == 'refs/tags/nightly' }} | |
| secrets: | |
| SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} | |
| package-parsec-desktop: | |
| needs: version | |
| # Do not run this job if the event is a pull request from dependabot. | |
| if: needs.version.result == 'success' && !(github.event_name == 'pull_request' && github.actor == 'dependabot[bot]') && always() | |
| uses: ./.github/workflows/package-desktop.yml | |
| with: | |
| version: ${{ needs.version.outputs.full }} | |
| version_patch_run_id: ${{ github.run_id }} | |
| commit_sha: ${{ needs.version.outputs.commit_sha }} | |
| nightly_build: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.ref == 'refs/tags/nightly' }} | |
| secrets: | |
| SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} | |
| MACOS_CI_KEYCHAIN_PASSWD: ${{ secrets.MACOS_CI_KEYCHAIN_PASSWD }} | |
| MACOS_CERT_PASSWD: ${{ secrets.MACOS_CERT_PASSWD }} | |
| MACOS_CERT: ${{ secrets.MACOS_CERT }} | |
| MACOS_CERT_COMMON_NAME: ${{ secrets.MACOS_CERT_COMMON_NAME }} | |
| MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }} | |
| MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.MACOS_NOTARIZATION_APPLE_ID }} | |
| MACOS_NOTARIZATION_PASSWD: ${{ secrets.MACOS_NOTARIZATION_PASSWD }} | |
| package-parsec-cli: | |
| needs: version | |
| if: needs.version.result == 'success' && always() | |
| uses: ./.github/workflows/package-cli.yml | |
| with: | |
| version: ${{ needs.version.outputs.full }} | |
| version_patch_run_id: ${{ github.run_id }} | |
| commit_sha: ${{ needs.version.outputs.commit_sha }} | |
| releaser: | |
| needs: | |
| - version | |
| - package-parsec-server | |
| - package-parsec-webapp | |
| - package-parsec-desktop | |
| - package-parsec-cli | |
| name: 🚛 Releaser | |
| permissions: | |
| contents: write | |
| if: >- | |
| needs.version.result == 'success' | |
| && needs.package-parsec-desktop.result == 'success' | |
| && needs.package-parsec-webapp.result == 'success' | |
| && needs.package-parsec-server.result == 'success' | |
| && needs.package-parsec-cli.result == 'success' | |
| && always() | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - name: Download every artifact generated (and uploaded) | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # pin v8.0.1 | |
| with: | |
| path: artifacts | |
| digest-mismatch: error | |
| timeout-minutes: 5 | |
| - name: List downloaded artifacts | |
| run: tree artifacts | |
| - name: Create the folder that will contain the release files | |
| run: mkdir release-files | |
| - name: Copy artifacts to the release folder | |
| run: | | |
| set -ex | |
| # Python Files | |
| cp ${CP_ARGS} artifacts/*-wheel/parsec_cloud-${{ needs.version.outputs.pep440 }}-*.whl release-files | |
| cp ${CP_ARGS} artifacts/Linux-X64-wheel/requirements.txt release-files/python-linux-requirements.txt | |
| cp ${CP_ARGS} artifacts/macOS-ARM64-wheel/requirements.txt release-files/python-macos-requirements.txt | |
| cp ${CP_ARGS} artifacts/Windows-X64-wheel/requirements.txt release-files/python-win-requirements.txt | |
| # Copy electron apps & latest files | |
| cp ${CP_ARGS} artifacts/*-electron/Parsec_${{ needs.version.outputs.full }}_* release-files | |
| cp ${CP_ARGS} artifacts/*-electron/latest-*.yml release-files | |
| # TODO: Currently, Windows electron client is not signed by the CI, thus | |
| # it should not be uploaded when creating the draft release. | |
| # These artifacts are uploaded manually by someone who is able to sign them. | |
| # # EXE | |
| # cp ${CP_ARGS} artifacts/windows-exe-X64-electron/Parsec_${{ needs.version.outputs.full }}_win_*.unsigned.exe{,.blockmap} release-files | |
| # cp ${CP_ARGS} artifacts/windows-exe-X64-electron/latest-win-*.yml release-files | |
| # Copy client CLI | |
| cp ${CP_ARGS} artifacts/cli-*/parsec-cli-${{ needs.version.outputs.full }}-* release-files | |
| # Webapp | |
| cp ${CP_ARGS} artifacts/webapp/parsec-web-${{ needs.version.outputs.full }}.zip release-files | |
| env: | |
| # TODO: Current version of cp don't support `--update` with argument, | |
| # recent version (coreutils-9.5) allows for `none-fail` that make `cp` fail if it would have overwritten a file. | |
| CP_ARGS: -v --no-clobber | |
| BASH_XTRACEFD: 1 | |
| - name: Copy SBOM files | |
| run: cp -v --no-clobber artifacts/**/Parsec-SBOM-*.spdx.json release-files | |
| - name: Merge artifacts files | |
| id: artifacts | |
| shell: bash -eux -o pipefail {0} | |
| # cspell:words ireduce | |
| run: | | |
| yq eval-all '. as $item ireduce ({}; . * $item)' $(find artifacts -name artifacts.yml) | tee artifacts.yml | |
| ( | |
| echo 'files_to_upload<<EOF_files_to_upload' | |
| # Get the leaf values of the artifacts.yml file. | |
| # This correspond to filename that need to be uploaded. | |
| # But we need to add the prefix `release-files` | |
| yq . artifacts.yml -o json | jq -r '"release-files/" + (.. | scalars)' | grep -v 'Parsec_.*_win_.*.unsigned.exe' | |
| echo 'EOF_files_to_upload' | |
| ) | tee -a $GITHUB_OUTPUT | |
| - name: Generate version file | |
| run: | |
| ( | |
| echo "full=${{ needs.version.outputs.full }}"; | |
| echo "pep440=${{ needs.version.outputs.pep440 }}"; | |
| echo "major=${{ needs.version.outputs.major }}"; | |
| echo "minor=${{ needs.version.outputs.minor }}"; | |
| echo "patch=${{ needs.version.outputs.patch }}"; | |
| echo "pre=${{ needs.version.outputs.pre }}"; | |
| echo "dev=${{ needs.version.outputs.dev }}"; | |
| echo "local=${{ needs.version.outputs.local }}"; | |
| ) | tee release-files/version | |
| - name: List files in 'release-files'. | |
| run: tree release-files | |
| - name: Generate checksums file for released files | |
| run: sha256sum * | tee ../checksums.sha256 | |
| working-directory: release-files | |
| - name: Generate data for release | |
| id: info | |
| shell: bash -e -o pipefail {0} | |
| run: | | |
| ( | |
| echo 'tag_name=${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && 'nightly' || github.ref_name }}' | |
| echo 'release_name=${{ env.NIGHTLY_RELEASE == 'true' && 'Nightly release' || format('Release v{0}', needs.version.outputs.full) }}' | |
| echo 'repo_path=${{ github.server_url }}/${{ github.repository }}' | |
| ) | tee -a $GITHUB_OUTPUT | |
| timeout-minutes: 1 | |
| - name: Generate summary | |
| id: summary | |
| run: | | |
| EOF="EOF-$(dd if=/dev/urandom bs=15 count=1 status=none | base64)" | |
| ( | |
| set -eu -o pipefail | |
| function asset_name { yq -r "$1" artifacts.yml; } | |
| function gen_mk_dl_link { local name=$(asset_name "$1"); echo "[$name]($ASSET_DL_PATH/$name)"; } | |
| echo "output<<$EOF" | |
| echo '# Parsec ${{ needs.version.outputs.full }}' | |
| echo | |
| echo '## Client' | |
| echo | |
| echo '| Platform | Download link |' | |
| echo '| ---------------- | ------------- |' | |
| echo "| Windows | [Parsec_${{ needs.version.outputs.full }}_win_x86_64.exe]($ASSET_DL_PATH/Parsec_${{ needs.version.outputs.full }}_win_x86_64.exe) |" | |
| echo "| Macos (intel) | $(gen_mk_dl_link ".macos.x86_64.client.dmg") |" | |
| echo "| Macos (ARM) | $(gen_mk_dl_link ".macos.arm64.client.dmg") |" | |
| echo "| Linux (AppImage) | $(gen_mk_dl_link ".linux-gnu.x86_64.client.AppImage") |" | |
| echo "| Linux (Snap) | $(gen_mk_dl_link ".linux-gnu.x86_64.client.snap") |" | |
| echo "| WebApp | $(gen_mk_dl_link ".webapp") |" | |
| echo | |
| echo '> AppImage support is currently in alpha, you are likely to encounter crashes' | |
| echo '> if your Linux distribution differs too much from Ubuntu 24.04.' | |
| echo | |
| echo '## Server' | |
| echo | |
| echo '| Platform | Download link |' | |
| echo '| ---------------- | ------------- |' | |
| echo "| Windows | $(gen_mk_dl_link ".windows.x86_64.server") |" | |
| echo "| Macos | $(gen_mk_dl_link ".macos.arm64.server") |" | |
| echo "| Linux | $(gen_mk_dl_link ".linux-gnu.x86_64.server") |" | |
| echo | |
| echo '> We provide the wheel for _Windows_ & _Macos_ as best effort basis,' | |
| echo '> we only test and use the linux wheel.' | |
| echo | |
| echo '## CLI' | |
| echo | |
| echo '| Platform | Download link |' | |
| echo '| --------------- | ------------- |' | |
| echo "| Linux (static) | $(gen_mk_dl_link ".linux-musl.x86_64.cli") |" | |
| echo "| Linux (dynamic) | $(gen_mk_dl_link ".linux-gnu.x86_64.cli") |" | |
| echo | |
| echo '## Verifying the assets' | |
| echo | |
| echo 'You can verify the downloaded assets with the following command:' | |
| echo | |
| echo '```shell' | |
| echo 'sha256sum -c checksums.sha256 --ignore-missing' | |
| echo '```' | |
| echo | |
| echo '> The Windows files does not have a checksum because they are signed manually' | |
| echo | |
| echo "You can [download \`checksums.sha256\`]($ASSET_DL_PATH/checksums.sha256) or copy the following content into \`checksums.sha256\`:" | |
| echo | |
| echo '```txt' | |
| cat checksums.sha256 | |
| echo '```' | |
| echo | |
| echo --- | |
| echo | |
| echo 'Generated by <${{ steps.info.outputs.repo_path }}/actions/runs/${{ github.run_id }}>' | |
| echo "$EOF" | |
| ) | tee -a $GITHUB_OUTPUT | |
| env: | |
| ASSET_DL_PATH: ${{ steps.info.outputs.repo_path }}/releases/download/${{ steps.info.outputs.tag_name }} | |
| - name: Remove previous nightly release | |
| if: env.NIGHTLY_RELEASE == 'true' | |
| run: | | |
| if gh release ${{ env.GH_ARGS }} view nightly; then | |
| gh release ${{ env.GH_ARGS }} delete nightly | |
| else | |
| echo "No nightly release to remove" | |
| fi | |
| env: | |
| GH_ARGS: --repo=${{ steps.info.outputs.repo_path }} | |
| GH_TOKEN: ${{ github.token }} | |
| - name: Checkout the repository to update the nightly tag | |
| if: env.NIGHTLY_RELEASE == 'true' | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # pin v7.0.1 | |
| with: | |
| ref: ${{ needs.version.outputs.commit_sha }} | |
| path: parsec-cloud | |
| timeout-minutes: 5 | |
| - name: Update the nightly tag | |
| if: env.NIGHTLY_RELEASE == 'true' | |
| run: | | |
| git tag --force nightly ${{ needs.version.outputs.commit_sha }} | |
| git push --force origin refs/tags/nightly | |
| working-directory: parsec-cloud | |
| - name: Create release | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) | |
| uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # pin v3.0.2 | |
| with: | |
| draft: ${{ env.NIGHTLY_RELEASE != 'true' }} | |
| tag_name: ${{ steps.info.outputs.tag_name }} | |
| body: ${{ steps.summary.outputs.output }} | |
| prerelease: ${{ needs.version.outputs.pre != '' || needs.version.outputs.dev != '' || needs.version.outputs.local != '' }} | |
| name: ${{ steps.info.outputs.release_name }} | |
| files: | | |
| ${{ steps.artifacts.outputs.files_to_upload }} | |
| release-files/python-*-requirements.txt | |
| release-files/latest-*.yml | |
| release-files/Parsec-SBOM-*.spdx.json | |
| release-files/version | |
| checksums.sha256 | |
| fail_on_unmatched_files: true | |
| generate_release_notes: false | |
| timeout-minutes: 5 | |
| publish: | |
| needs: releaser | |
| # Only publish after release if the release is for a nightly build. | |
| # We only do that for nightly because we do not create the github release as draft for nightlies to limit the need to human interventions. | |
| if: >- | |
| (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/tags/nightly')) | |
| && needs.releaser.result == 'success' | |
| && always() | |
| uses: ./.github/workflows/publish.yml | |
| permissions: | |
| contents: read | |
| id-token: write | |
| with: | |
| release_tag: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && 'nightly' || github.ref_name }} | |
| nightly: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' || github.ref == 'refs/tags/nightly' }} | |
| secrets: | |
| SNAPCRAFT_CREDENTIALS: ${{ secrets.SNAPCRAFT_CREDENTIALS }} | |
| PYPI_CREDENTIALS: ${{ secrets.PYPI_CREDENTIALS }} |