TEMPORARY: isolate generate_changelogs for e2e test #5
Workflow file for this run
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
| # A reusable workflow that encapsulates all of the logic surrounding building | ||
| # all bundles for a single release channel, either new releases (when run on the | ||
| # `master` branch) or updated release candidates (when run within a `*_release` | ||
| # branch). | ||
| # | ||
| # This can either be triggered: | ||
| # * Indirectly, using workflow_call, for creating real releases. | ||
| # * Directly, using workflow_dispatch, for testing. By default, this will not create GitHub or Sentry releases, or upload to GCS. | ||
| name: Create Release | ||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| channel: | ||
| description: The channel to create a release or release candidate for. | ||
| required: true | ||
| type: string | ||
| build_linux: | ||
| description: Build Linux artifacts. | ||
| type: boolean | ||
| default: true | ||
| build_windows: | ||
| description: Build Windows artifacts. | ||
| type: boolean | ||
| default: true | ||
| build_macos: | ||
| description: Build macOS artifacts. | ||
| type: boolean | ||
| default: true | ||
| build_web: | ||
| description: Build web artifacts. | ||
| type: boolean | ||
| default: true | ||
| should_publish: | ||
| description: Publish this release | ||
| type: boolean | ||
| default: true | ||
| workflow_dispatch: | ||
| inputs: | ||
| channel: | ||
| type: string | ||
| required: true | ||
| build_linux: | ||
| description: Build Linux artifacts. | ||
| type: boolean | ||
| default: true | ||
| build_windows: | ||
| description: Build Windows artifacts. | ||
| type: boolean | ||
| default: true | ||
| build_macos: | ||
| description: Build macOS artifacts. | ||
| type: boolean | ||
| default: true | ||
| build_web: | ||
| description: Build web artifacts. | ||
| type: boolean | ||
| default: true | ||
| env: | ||
| CARGO_TERM_COLOR: always | ||
| CONFIG_FILE: ".github/workflows/release_configurations.json" | ||
| jobs: | ||
| # Perform all once-per-release steps. Dependent jobs will build release | ||
| # assets and upload them as appropriate. | ||
| prepare_release: | ||
| name: Prepare release | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| release_branch: ${{ steps.create_branch_and_tag.outputs.branch }} | ||
| release_tag: ${{ steps.create_branch_and_tag.outputs.tag }} | ||
| should_publish: ${{ steps.set_publish.outputs.should_publish }} | ||
| steps: | ||
| - name: Checkout sources | ||
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| - name: Get channel configuration | ||
| id: get-config | ||
| uses: ./.github/actions/get_channel_config/ | ||
| with: | ||
| config_file: ${{ env.CONFIG_FILE }} | ||
| channel: ${{ inputs.channel }} | ||
| - name: Set publish flag based on the workflow trigger | ||
| id: set_publish | ||
| run: | | ||
| # The should_publish input is only set on the workflow_call trigger. | ||
| # This means it's not possible to trigger publishing via workflow_dispatch, and | ||
| # publishing is enabled by default when called for a new release or RC. | ||
| if [[ "${{ inputs.should_publish }}" == "true" ]]; then | ||
| echo "should_publish=true" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "should_publish=false" >> $GITHUB_OUTPUT | ||
| fi | ||
| shell: bash | ||
| - name: Update branch and tag | ||
| id: create_branch_and_tag | ||
| run: | | ||
| if [[ "${{ steps.set_publish.outputs.should_publish }}" == "true" ]]; then | ||
| GIT_BRANCH_NAME="${GITHUB_REF#refs/heads/}" | ||
| source ./script/create_release_tag_and_branch --channel $CHANNEL --branch-name "$GIT_BRANCH_NAME" | ||
| echo "branch=$(git branch --show-current)" >> $GITHUB_OUTPUT | ||
| echo "tag=$tag" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "branch=$(git branch --show-current)" >> $GITHUB_OUTPUT | ||
| # Use a fake version tag that will pass package validation. | ||
| echo "tag=v0.$GITHUB_SHA" >> $GITHUB_OUTPUT | ||
| fi | ||
| shell: bash | ||
| env: | ||
| CHANNEL: ${{ steps.get-config.outputs.channel }} | ||
| # See https://github.com/orgs/community/discussions/151442 for why we need to use | ||
| # a PAT here. | ||
| GITHUB_TOKEN: ${{ secrets.CREATE_RELEASE_TAG_PUSH_PAT }} | ||
| - name: Create GitHub release | ||
| if: ${{ steps.set_publish.outputs.should_publish == 'true' }} | ||
| id: create_release | ||
| uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 | ||
| with: | ||
| name: ${{ steps.get-config.outputs.release_base_name }} ${{ steps.create_branch_and_tag.outputs.tag }} | ||
| tag_name: ${{ steps.create_branch_and_tag.outputs.tag }} | ||
| body: ${{ steps.get-config.outputs.release_body_text }} | ||
| draft: false | ||
| prerelease: ${{ steps.get-config.outputs.is_prerelease }} | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Create Sentry release | ||
| if: ${{ steps.set_publish.outputs.should_publish == 'true' }} | ||
| uses: getsentry/action-release@5657c9e888b4e2cc85f4d29143ea4131fde4a73a # v3.6.0 | ||
| env: | ||
| SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_RELEASE_TOKEN }} | ||
| SENTRY_ORG: warpdotdev | ||
| SENTRY_PROJECT: ${{ steps.get-config.outputs.sentry_project }} | ||
| with: | ||
| environment: ${{ steps.get-config.outputs.sentry_environment }} | ||
| version: ${{ steps.create_branch_and_tag.outputs.tag }} | ||
| # ==================== TEMPORARILY COMMENTED OUT FOR CHANGELOG TEST ==================== | ||
| # All build jobs and slack notification commented out to test generate_changelogs in isolation. | ||
| # REVERT THIS COMMIT BEFORE MERGING. | ||
| # ====================================================================================== | ||
| _placeholder_for_commented_jobs: | ||
| name: Placeholder (build jobs commented out for test) | ||
| runs-on: ubuntu-latest | ||
| if: false | ||
| steps: | ||
| - run: echo skip | ||
| DISABLED_release_macos_single_arch: | ||
| name: Build Release (macOS ${{ matrix.dmg_name_suffix }}) | ||
| runs-on: macos-26-xlarge | ||
| needs: prepare_release | ||
| if: ${{ inputs.build_macos != false }} | ||
| timeout-minutes: 60 | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - arch: aarch64 | ||
| dmg_name_suffix: arm64 | ||
| - arch: x86_64 | ||
| dmg_name_suffix: x86_64 | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| - uses: ./.github/actions/prepare_environment | ||
| with: | ||
| target_os: macos | ||
| is_self_hosted: false | ||
| ref: ${{ needs.prepare_release.outputs.release_branch }} | ||
| install_release_deps: true | ||
| ssh_key: ${{ secrets.WARP_CHANNEL_CONFIG_ACCESS_SSH_KEY }} | ||
| - name: Ensure rust target is installed | ||
| run: rustup target add ${{ matrix.arch }}-apple-darwin | ||
| shell: bash | ||
| # Install go toolchain, as it may be needed for some build steps. | ||
| - name: Setup Go | ||
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 | ||
| with: | ||
| go-version: stable | ||
| - name: Get channel configuration | ||
| id: get-config | ||
| uses: ./.github/actions/get_channel_config/ | ||
| with: | ||
| config_file: ${{ env.CONFIG_FILE }} | ||
| channel: ${{ inputs.channel }} | ||
| - name: Install cargo-bundle | ||
| run: script/install_cargo_bundle | ||
| - name: Install create-dmg | ||
| run: brew install create-dmg | ||
| - name: Build ${{ matrix.arch }} bundle | ||
| id: bundle_app | ||
| run: | | ||
| script/bundle --read-passwords-from-env --channel $CHANNEL --arch ${{ matrix.arch }} --dmg-name-suffix "${{ matrix.dmg_name_suffix }}" | ||
| shell: bash | ||
| env: | ||
| CHANNEL: ${{ steps.get-config.outputs.channel }} | ||
| GIT_RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }} | ||
| WARP_DEVELOPER_ID_CERT: ${{ secrets.WARP_DEVELOPER_ID_CERT }} | ||
| WARP_DEVELOPER_ID_CERT_PASSWORD: ${{ secrets.WARP_DEVELOPER_ID_CERT_PASSWORD }} | ||
| WARP_CODESIGN_KEYCHAIN_PASSWORD: ${{ secrets.WARP_CODESIGN_KEYCHAIN_PASSWORD }} | ||
| WARP_NOTARIZATION_APPLE_ID: ${{ secrets.WARP_NOTARIZATION_APPLE_ID }} | ||
| WARP_NOTARIZATION_PASSWORD: ${{ secrets.WARP_NOTARIZATION_PASSWORD }} | ||
| - name: Add DMG to GitHub release assets | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 | ||
| with: | ||
| tag_name: ${{ needs.prepare_release.outputs.release_tag }} | ||
| files: ${{ steps.bundle_app.outputs.dmg_path }} | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| with: | ||
| credentials_json: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} | ||
| - name: Upload DMG to Google Cloud Storage | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: google-github-actions/upload-cloud-storage@e95a15f226403ed658d3e65f40205649f342ba2c # v1 | ||
| with: | ||
| path: ${{ steps.bundle_app.outputs.dmg_path }} | ||
| destination: warp-releases/${{ steps.get-config.outputs.channel }}/${{ needs.prepare_release.outputs.release_tag }} | ||
| headers: |- | ||
| cache-control: ${{ steps.get-config.outputs.gcs_cache_control_value }} | ||
| - name: Upload DMG as workflow artifact | ||
| if: ${{ needs.prepare_release.outputs.should_publish != 'true' }} | ||
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | ||
| with: | ||
| name: release-macos-${{ matrix.arch }}-${{ steps.get-config.outputs.channel }} | ||
| path: ${{ steps.bundle_app.outputs.dmg_path }} | ||
| - name: Set up Sentry CLI | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b # v2.0.0 | ||
| with: | ||
| token: ${{ secrets.SENTRY_RELEASE_TOKEN }} | ||
| organization: warpdotdev | ||
| project: ${{ steps.get-config.outputs.sentry_project }} | ||
| - name: Upload debug symbols from frameworks to Sentry | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| run: | | ||
| script/sentry_upload_dif.sh | ||
| shell: bash | ||
| env: | ||
| DEBUG_FILE_OR_FOLDER_PATH: ${{ steps.bundle_app.outputs.frameworks_dir }} | ||
| # Create a tar archive instead of simply using upload-artifact so we can | ||
| # preserve permissions and symlinks. If we don't preserve symlinks, we'll | ||
| # break the macOS framework directory structure. | ||
| - name: Create tar archive with build artifacts | ||
| run: | | ||
| tar czfv build-artifacts.tar.gz \ | ||
| ${{ steps.bundle_app.outputs.binary_path }} \ | ||
| ${{ steps.bundle_app.outputs.dock_tile_plugin_dir }} \ | ||
| ${{ steps.bundle_app.outputs.dsym_path }} \ | ||
| ${{ steps.bundle_app.outputs.dsym_realpath }} \ | ||
| ${{ steps.bundle_app.outputs.frameworks_dir }} | ||
| - name: Archive ${{ matrix.arch }} build artifacts for universal build | ||
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | ||
| with: | ||
| name: macos-${{ matrix.arch }}-${{ steps.get-config.outputs.channel }} | ||
| retention-days: 1 | ||
| # We compress the tar archive, so no need to re-compress. | ||
| compression-level: 0 | ||
| path: build-artifacts.tar.gz | ||
| release_macos_universal: | ||
| name: Build Release (macOS Universal) | ||
| runs-on: macos-26-xlarge | ||
| needs: [prepare_release, release_macos_single_arch] | ||
| if: ${{ inputs.build_macos != false }} | ||
| timeout-minutes: 60 | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| - uses: ./.github/actions/prepare_environment | ||
| with: | ||
| target_os: macos | ||
| is_self_hosted: false | ||
| ref: ${{ needs.prepare_release.outputs.release_branch }} | ||
| install_release_deps: true | ||
| ssh_key: ${{ secrets.WARP_CHANNEL_CONFIG_ACCESS_SSH_KEY }} | ||
| # Install go toolchain, as it may be needed for some build steps. | ||
| - name: Setup Go | ||
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 | ||
| with: | ||
| go-version: stable | ||
| - name: Get channel configuration | ||
| id: get-config | ||
| uses: ./.github/actions/get_channel_config/ | ||
| with: | ||
| config_file: ${{ env.CONFIG_FILE }} | ||
| channel: ${{ inputs.channel }} | ||
| - name: Download aarch64 build artifacts | ||
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | ||
| with: | ||
| name: macos-aarch64-${{ steps.get-config.outputs.channel }} | ||
| - name: Extract aarch64 build artifacts | ||
| run: tar xvfz build-artifacts.tar.gz | ||
| shell: bash | ||
| - name: Download x86_64 build artifacts | ||
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | ||
| with: | ||
| name: macos-x86_64-${{ steps.get-config.outputs.channel }} | ||
| - name: Extract x86_64 build artifacts | ||
| run: tar xvfz build-artifacts.tar.gz | ||
| shell: bash | ||
| - name: Install cargo-bundle | ||
| run: script/install_cargo_bundle | ||
| - name: Install create-dmg | ||
| run: brew install create-dmg | ||
| - name: Bundle universal app | ||
| id: bundle_app | ||
| run: | | ||
| script/bundle --skip-build --read-passwords-from-env --channel $CHANNEL | ||
| shell: bash | ||
| env: | ||
| CHANNEL: ${{ steps.get-config.outputs.channel }} | ||
| GIT_RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }} | ||
| WARP_DEVELOPER_ID_CERT: ${{ secrets.WARP_DEVELOPER_ID_CERT }} | ||
| WARP_DEVELOPER_ID_CERT_PASSWORD: ${{ secrets.WARP_DEVELOPER_ID_CERT_PASSWORD }} | ||
| WARP_CODESIGN_KEYCHAIN_PASSWORD: ${{ secrets.WARP_CODESIGN_KEYCHAIN_PASSWORD }} | ||
| WARP_NOTARIZATION_APPLE_ID: ${{ secrets.WARP_NOTARIZATION_APPLE_ID }} | ||
| WARP_NOTARIZATION_PASSWORD: ${{ secrets.WARP_NOTARIZATION_PASSWORD }} | ||
| - name: Set up Sentry CLI | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b # v2.0.0 | ||
| with: | ||
| token: ${{ secrets.SENTRY_RELEASE_TOKEN }} | ||
| organization: warpdotdev | ||
| project: ${{ steps.get-config.outputs.sentry_project }} | ||
| - name: Upload debugging symbols to Sentry | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| run: | | ||
| script/sentry_upload_dif.sh | ||
| shell: bash | ||
| env: | ||
| DEBUG_FILE_OR_FOLDER_PATH: ${{ steps.bundle_app.outputs.dsym_folder_path }} | ||
| - name: Add DMG to GitHub release assets | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| id: upload_github_assets | ||
| uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 | ||
| # Continue if the upload fails; the next step will retry it. | ||
| continue-on-error: true | ||
| with: | ||
| tag_name: ${{ needs.prepare_release.outputs.release_tag }} | ||
| files: ${{ steps.bundle_app.outputs.dmg_path }} | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Add DMG to GitHub release assets (retry 1/2) | ||
| id: upload_github_assets_retry | ||
| # If the first attempt failed, try again. | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' && steps.upload_github_assets.outcome == 'failure' }} | ||
| # Continue if the upload fails; the next step will retry it. | ||
| continue-on-error: true | ||
| uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 | ||
| with: | ||
| tag_name: ${{ needs.prepare_release.outputs.release_tag }} | ||
| files: ${{ steps.bundle_app.outputs.dmg_path }} | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Add DMG to GitHub release assets (retry 2/2) | ||
| id: upload_github_assets_retry2 | ||
| # If the first attempt failed, try again. | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' && steps.upload_github_assets_retry.outcome == 'failure' }} | ||
| uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 | ||
| with: | ||
| tag_name: ${{ needs.prepare_release.outputs.release_tag }} | ||
| files: ${{ steps.bundle_app.outputs.dmg_path }} | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| with: | ||
| credentials_json: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} | ||
| - name: Upload DMG to Google Cloud Storage | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: google-github-actions/upload-cloud-storage@e95a15f226403ed658d3e65f40205649f342ba2c # v1 | ||
| with: | ||
| path: ${{ steps.bundle_app.outputs.dmg_path }} | ||
| destination: warp-releases/${{ steps.get-config.outputs.channel }}/${{ needs.prepare_release.outputs.release_tag }} | ||
| # IMPORTANT: both the key and value of the cache-control header must be all lowercase; | ||
| # uppercase values will not be respected by Cloud CDN and using "Cache-Control" will be | ||
| # ignored by the upload-cloud-storage action. | ||
| headers: |- | ||
| cache-control: ${{ steps.get-config.outputs.gcs_cache_control_value }} | ||
| - name: Upload DMG as workflow artifact | ||
| if: ${{ needs.prepare_release.outputs.should_publish != 'true' }} | ||
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | ||
| with: | ||
| name: release-macos-universal-${{ steps.get-config.outputs.channel }} | ||
| path: ${{ steps.bundle_app.outputs.dmg_path }} | ||
| release_macos_cli: | ||
| name: Build Release (macOS CLI ${{ matrix.arch }}) | ||
| runs-on: macos-26-xlarge | ||
| needs: prepare_release | ||
| if: ${{ inputs.build_macos != false }} | ||
| timeout-minutes: 60 | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - arch: aarch64 | ||
| - arch: x86_64 | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| - uses: ./.github/actions/prepare_environment | ||
| with: | ||
| target_os: macos | ||
| is_self_hosted: false | ||
| ref: ${{ needs.prepare_release.outputs.release_branch }} | ||
| install_release_deps: true | ||
| ssh_key: ${{ secrets.WARP_CHANNEL_CONFIG_ACCESS_SSH_KEY }} | ||
| - name: Ensure rust target is installed | ||
| run: rustup target add ${{ matrix.arch }}-apple-darwin | ||
| shell: bash | ||
| # Install go toolchain, as it may be needed for some build steps. | ||
| - name: Setup Go | ||
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 | ||
| with: | ||
| go-version: stable | ||
| - name: Get channel configuration | ||
| id: get-config | ||
| uses: ./.github/actions/get_channel_config/ | ||
| with: | ||
| config_file: ${{ env.CONFIG_FILE }} | ||
| channel: ${{ inputs.channel }} | ||
| - name: Build ${{ matrix.arch }} binary | ||
| id: bundle_cli | ||
| run: | | ||
| script/bundle --read-passwords-from-env --channel $CHANNEL --arch ${{ matrix.arch }} --artifact cli | ||
| shell: bash | ||
| env: | ||
| CHANNEL: ${{ steps.get-config.outputs.channel }} | ||
| GIT_RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }} | ||
| WARP_DEVELOPER_ID_CERT: ${{ secrets.WARP_DEVELOPER_ID_CERT }} | ||
| WARP_DEVELOPER_ID_CERT_PASSWORD: ${{ secrets.WARP_DEVELOPER_ID_CERT_PASSWORD }} | ||
| WARP_CODESIGN_KEYCHAIN_PASSWORD: ${{ secrets.WARP_CODESIGN_KEYCHAIN_PASSWORD }} | ||
| WARP_NOTARIZATION_APPLE_ID: ${{ secrets.WARP_NOTARIZATION_APPLE_ID }} | ||
| WARP_NOTARIZATION_PASSWORD: ${{ secrets.WARP_NOTARIZATION_PASSWORD }} | ||
| - name: Package CLI binary | ||
| run: | | ||
| mv ${{ steps.bundle_cli.outputs.binary_path }} oz-${{ steps.get-config.outputs.channel }} | ||
| tar czf oz-${{ steps.get-config.outputs.channel }}-macos-${{ matrix.arch }}.tar.gz oz-${{ steps.get-config.outputs.channel }} -C "$(dirname "${{ steps.bundle_cli.outputs.bundled_resources_dir }}")" resources | ||
| - name: Add CLI to GitHub release assets | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 | ||
| with: | ||
| tag_name: ${{ needs.prepare_release.outputs.release_tag }} | ||
| files: oz-${{ steps.get-config.outputs.channel }}-macos-${{ matrix.arch }}.tar.gz | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| with: | ||
| credentials_json: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} | ||
| - name: Upload CLI to Google Cloud Storage | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: google-github-actions/upload-cloud-storage@e95a15f226403ed658d3e65f40205649f342ba2c # v1 | ||
| with: | ||
| path: oz-${{ steps.get-config.outputs.channel }}-macos-${{ matrix.arch }}.tar.gz | ||
| destination: warp-releases/${{ steps.get-config.outputs.channel }}/${{ needs.prepare_release.outputs.release_tag }}/cli/macos/${{ matrix.arch }} | ||
| headers: |- | ||
| cache-control: ${{ steps.get-config.outputs.gcs_cache_control_value }} | ||
| - name: Upload CLI as workflow artifact | ||
| if: ${{ needs.prepare_release.outputs.should_publish != 'true' }} | ||
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | ||
| with: | ||
| name: release-macos-cli-${{ matrix.arch }}-${{ steps.get-config.outputs.channel }} | ||
| path: oz-${{ steps.get-config.outputs.channel }}-macos-${{ matrix.arch }}.tar.gz | ||
| - name: Set up Sentry CLI | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b # v2.0.0 | ||
| with: | ||
| token: ${{ secrets.SENTRY_RELEASE_TOKEN }} | ||
| organization: warpdotdev | ||
| project: ${{ steps.get-config.outputs.sentry_project }} | ||
| - name: Upload debugging symbols to Sentry | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| run: | | ||
| script/sentry_upload_dif.sh | ||
| shell: bash | ||
| env: | ||
| DEBUG_FILE_OR_FOLDER_PATH: ${{ steps.bundle_cli.outputs.dsym_path }} | ||
| release_linux_x86: | ||
| name: Build Release (Linux x86_64) | ||
| runs-on: namespace-profile-ubuntu-20-04 | ||
| needs: prepare_release | ||
| if: ${{ inputs.build_linux != false }} | ||
| timeout-minutes: 90 | ||
| env: | ||
| # Automatically extract AppImages before running them instead of mounting | ||
| # them with FUSE, which isn't available on GitHub runners (and this is | ||
| # easier and less error-prone than trying to install it). | ||
| APPIMAGE_EXTRACT_AND_RUN: "1" | ||
| # Cache the generated settings schema so prepare_bundled_resources only | ||
| # compiles and runs the generator once per job instead of per-package. | ||
| SETTINGS_SCHEMA_CACHE: ${{ github.workspace }}/.settings_schema_cache.json | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| - uses: ./.github/actions/prepare_environment | ||
| with: | ||
| target_os: linux | ||
| is_self_hosted: false | ||
| ref: ${{ needs.prepare_release.outputs.release_branch }} | ||
| install_release_deps: true | ||
| ssh_key: ${{ secrets.WARP_CHANNEL_CONFIG_ACCESS_SSH_KEY }} | ||
| # Install gcc 10, as gcc 9.5 has a bug with memcmp that is incompatible | ||
| # with aws-lc-rs (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95189). | ||
| - name: Install and configure gcc-10 | ||
| run: | | ||
| sudo apt update | ||
| sudo apt install -y gcc-10 g++-10 | ||
| sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 60 --slave /usr/bin/g++ g++ /usr/bin/g++-10 | ||
| gcc --version | ||
| g++ --version | ||
| - name: Get channel configuration | ||
| id: get-config | ||
| uses: ./.github/actions/get_channel_config/ | ||
| with: | ||
| config_file: ${{ env.CONFIG_FILE }} | ||
| channel: ${{ inputs.channel }} | ||
| - uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 | ||
| with: | ||
| credentials_json: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} | ||
| - name: Install linuxdeploy | ||
| run: script/linux/install_linuxdeploy | ||
| - name: Load PGP signing key and passphrase | ||
| run: | | ||
| mkdir -p ~/.gnupg | ||
| echo "default-cache-ttl 7200" >> ~/.gnupg/gpg-agent.conf | ||
| # Set the appropriate permissions for files and directories. | ||
| find ~/.gnupg -type f -exec chmod 600 {} \; | ||
| find ~/.gnupg -type d -exec chmod 700 {} \; | ||
| # Test the agent configuration. This is helpful for debugging if | ||
| # something is invalid. | ||
| gpgconf --check-options gpg-agent | ||
| gpg-agent --gpgconf-test | ||
| # Kill the agent, if one is running, and then start a new one - this | ||
| # ensures our updated configuration is applied correctly. | ||
| gpgconf --kill gpg-agent | ||
| gpgconf --launch gpg-agent | ||
| # Retrieve our signing key and import it into gpg. | ||
| gcloud --project astral-field-294621 secrets versions access latest --secret=linux-releases-pgp-key | gpg --batch --import | ||
| # Populate the passphrase for our signing key in the gpg-agent cache. | ||
| # by signing an empty file. | ||
| touch emptyfile | ||
| gpg --no-tty --pinentry-mode loopback --passphrase-fd 0 --detach-sign --armor --batch --yes --output emptyfile.sig emptyfile << EOF | ||
| ${{ secrets.LINUX_RELEASES_PGP_KEY_PASSPHRASE }} | ||
| EOF | ||
| rm emptyfile.sig | ||
| shell: bash | ||
| # Namespace's User Bundled Cache persists target/ between jobs on the same profile, which can | ||
| # leave stale packages from a previous channel's build in the linux bundle output dir. | ||
| - name: Clean stale bundle output | ||
| run: rm -rf target/*/bundle/linux | ||
| shell: bash | ||
| - name: Bundle app | ||
| id: bundle_app | ||
| run: | | ||
| # Build everything but the arch package, as we need to build it | ||
| # within a Docker container. | ||
| script/bundle --channel $CHANNEL --packages appimage,deb,rpm | ||
| shell: bash | ||
| env: | ||
| CHANNEL: ${{ steps.get-config.outputs.channel }} | ||
| GIT_RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }} | ||
| - name: Bundle Arch Linux package | ||
| uses: ./.github/actions/bundle_arch_package | ||
| with: | ||
| channel: ${{ steps.get-config.outputs.channel }} | ||
| release-tag: ${{ needs.prepare_release.outputs.release_tag }} | ||
| arch: x86_64 | ||
| - name: Sign Arch Linux packages | ||
| run: | | ||
| ./script/linux/sign_arch_packages "$PKGDIR" | ||
| shell: bash | ||
| env: | ||
| PKGDIR: ${{ steps.bundle_app.outputs.packages_dir }} | ||
| - name: Set up Sentry CLI | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b # v2.0.0 | ||
| with: | ||
| token: ${{ secrets.SENTRY_RELEASE_TOKEN }} | ||
| organization: warpdotdev | ||
| project: ${{ steps.get-config.outputs.sentry_project }} | ||
| - name: Upload debugging symbols to Sentry | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| run: | | ||
| script/sentry_upload_dif.sh | ||
| shell: bash | ||
| env: | ||
| DEBUG_FILE_OR_FOLDER_PATH: ${{ steps.bundle_app.outputs.debug_executable_path }} | ||
| - name: Add packages to GitHub release assets | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| id: upload_github_assets | ||
| uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 | ||
| with: | ||
| tag_name: ${{ needs.prepare_release.outputs.release_tag }} | ||
| files: ${{ steps.bundle_app.outputs.packages_dir }}/* | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Upload packages to Google Cloud Storage | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: google-github-actions/upload-cloud-storage@e95a15f226403ed658d3e65f40205649f342ba2c # v1 | ||
| with: | ||
| path: ${{ steps.bundle_app.outputs.packages_dir }} | ||
| # Only upload the files from within `packages_dir`, don't include the | ||
| # (parent) folder itself. | ||
| parent: false | ||
| destination: warp-releases/${{ steps.get-config.outputs.channel }}/${{ needs.prepare_release.outputs.release_tag }} | ||
| # IMPORTANT: both the key and value of the cache-control header must be all lowercase; | ||
| # uppercase values will not be respected by Cloud CDN and using "Cache-Control" will be | ||
| # ignored by the upload-cloud-storage action. | ||
| headers: |- | ||
| cache-control: ${{ steps.get-config.outputs.gcs_cache_control_value }} | ||
| - name: Upload packages as workflow artifact | ||
| if: ${{ needs.prepare_release.outputs.should_publish != 'true' }} | ||
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | ||
| with: | ||
| name: release-linux-x86_64-${{ steps.get-config.outputs.channel }} | ||
| path: ${{ steps.bundle_app.outputs.packages_dir }} | ||
| release_linux_cli_x86: | ||
| name: Build Release (Linux CLI x86_64) | ||
| runs-on: namespace-profile-ubuntu-20-04 | ||
| needs: prepare_release | ||
| if: ${{ inputs.build_linux != false }} | ||
| timeout-minutes: 90 | ||
| env: | ||
| # Cache the generated settings schema so prepare_bundled_resources only | ||
| # compiles and runs the generator once per job instead of per-package. | ||
| SETTINGS_SCHEMA_CACHE: ${{ github.workspace }}/.settings_schema_cache.json | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| - uses: ./.github/actions/prepare_environment | ||
| with: | ||
| target_os: linux | ||
| is_self_hosted: false | ||
| ref: ${{ needs.prepare_release.outputs.release_branch }} | ||
| install_release_deps: true | ||
| ssh_key: ${{ secrets.WARP_CHANNEL_CONFIG_ACCESS_SSH_KEY }} | ||
| # Install gcc 10, as gcc 9.5 has a bug with memcmp that is incompatible | ||
| # with aws-lc-rs (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95189). | ||
| - name: Install and configure gcc-10 | ||
| run: | | ||
| sudo apt update | ||
| sudo apt install -y gcc-10 g++-10 | ||
| sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 60 --slave /usr/bin/g++ g++ /usr/bin/g++-10 | ||
| gcc --version | ||
| g++ --version | ||
| - name: Get channel configuration | ||
| id: get-config | ||
| uses: ./.github/actions/get_channel_config/ | ||
| with: | ||
| config_file: ${{ env.CONFIG_FILE }} | ||
| channel: ${{ inputs.channel }} | ||
| - uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 | ||
| with: | ||
| credentials_json: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} | ||
| - name: Load PGP signing key and passphrase | ||
| run: | | ||
| mkdir -p ~/.gnupg | ||
| echo "default-cache-ttl 7200" >> ~/.gnupg/gpg-agent.conf | ||
| # Set the appropriate permissions for files and directories. | ||
| find ~/.gnupg -type f -exec chmod 600 {} \; | ||
| find ~/.gnupg -type d -exec chmod 700 {} \; | ||
| # Test the agent configuration. This is helpful for debugging if | ||
| # something is invalid. | ||
| gpgconf --check-options gpg-agent | ||
| gpg-agent --gpgconf-test | ||
| # Kill the agent, if one is running, and then start a new one - this | ||
| # ensures our updated configuration is applied correctly. | ||
| gpgconf --kill gpg-agent | ||
| gpgconf --launch gpg-agent | ||
| # Retrieve our signing key and import it into gpg. | ||
| gcloud --project astral-field-294621 secrets versions access latest --secret=linux-releases-pgp-key | gpg --batch --import | ||
| # Populate the passphrase for our signing key in the gpg-agent cache. | ||
| # by signing an empty file. | ||
| touch emptyfile | ||
| gpg --no-tty --pinentry-mode loopback --passphrase-fd 0 --detach-sign --armor --batch --yes --output emptyfile.sig emptyfile << EOF | ||
| ${{ secrets.LINUX_RELEASES_PGP_KEY_PASSPHRASE }} | ||
| EOF | ||
| rm emptyfile.sig | ||
| shell: bash | ||
| # Namespace's User Bundled Cache persists target/ between jobs on the same profile, which can | ||
| # leave stale packages from a previous channel's build in the linux bundle output dir. | ||
| - name: Clean stale bundle output | ||
| run: rm -rf target/*/bundle/linux | ||
| shell: bash | ||
| - name: Bundle CLI | ||
| id: bundle_cli | ||
| run: | | ||
| # Build CLI only | ||
| script/bundle --channel $CHANNEL --artifact cli --packages deb,rpm | ||
| shell: bash | ||
| env: | ||
| CHANNEL: ${{ steps.get-config.outputs.channel }} | ||
| GIT_RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }} | ||
| - name: Package CLI tar.gz | ||
| run: | | ||
| cp ${{ steps.bundle_cli.outputs.executable_path }} oz-${{ steps.get-config.outputs.channel }} | ||
| tar czf oz-${{ steps.get-config.outputs.channel }}-linux-x86_64.tar.gz oz-${{ steps.get-config.outputs.channel }} -C "$(dirname "${{ steps.bundle_cli.outputs.bundled_resources_dir }}")" resources | ||
| - name: Bundle Arch Linux CLI package | ||
| uses: ./.github/actions/bundle_arch_package | ||
| with: | ||
| channel: ${{ steps.get-config.outputs.channel }} | ||
| release-tag: ${{ needs.prepare_release.outputs.release_tag }} | ||
| arch: x86_64 | ||
| artifact: cli | ||
| - name: Sign Arch Linux packages | ||
| run: | | ||
| ./script/linux/sign_arch_packages "$PKGDIR" | ||
| shell: bash | ||
| env: | ||
| PKGDIR: ${{ steps.bundle_cli.outputs.packages_dir }} | ||
| - name: Set up Sentry CLI | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b # v2.0.0 | ||
| with: | ||
| token: ${{ secrets.SENTRY_RELEASE_TOKEN }} | ||
| organization: warpdotdev | ||
| project: ${{ steps.get-config.outputs.sentry_project }} | ||
| - name: Upload debugging symbols to Sentry | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| run: | | ||
| script/sentry_upload_dif.sh | ||
| shell: bash | ||
| env: | ||
| DEBUG_FILE_OR_FOLDER_PATH: ${{ steps.bundle_cli.outputs.debug_executable_path }} | ||
| - name: Add CLI packages to GitHub release assets | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| id: upload_github_assets | ||
| uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 | ||
| with: | ||
| tag_name: ${{ needs.prepare_release.outputs.release_tag }} | ||
| files: ${{ steps.bundle_cli.outputs.packages_dir }}/* | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Upload CLI packages to Google Cloud Storage | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: google-github-actions/upload-cloud-storage@e95a15f226403ed658d3e65f40205649f342ba2c # v1 | ||
| with: | ||
| path: ${{ steps.bundle_cli.outputs.packages_dir }} | ||
| # Only upload the files from within `packages_dir`, don't include the | ||
| # (parent) folder itself. | ||
| parent: false | ||
| destination: warp-releases/${{ steps.get-config.outputs.channel }}/${{ needs.prepare_release.outputs.release_tag }} | ||
| # IMPORTANT: both the key and value of the cache-control header must be all lowercase; | ||
| # uppercase values will not be respected by Cloud CDN and using "Cache-Control" will be | ||
| # ignored by the upload-cloud-storage action. | ||
| headers: |- | ||
| cache-control: ${{ steps.get-config.outputs.gcs_cache_control_value }} | ||
| - name: Add CLI tar.gz to GitHub release assets | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 | ||
| with: | ||
| tag_name: ${{ needs.prepare_release.outputs.release_tag }} | ||
| files: oz-${{ steps.get-config.outputs.channel }}-linux-x86_64.tar.gz | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Upload CLI tar.gz to Google Cloud Storage | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: google-github-actions/upload-cloud-storage@e95a15f226403ed658d3e65f40205649f342ba2c # v1 | ||
| with: | ||
| path: oz-${{ steps.get-config.outputs.channel }}-linux-x86_64.tar.gz | ||
| destination: warp-releases/${{ steps.get-config.outputs.channel }}/${{ needs.prepare_release.outputs.release_tag }}/cli/linux/x86_64 | ||
| headers: |- | ||
| cache-control: ${{ steps.get-config.outputs.gcs_cache_control_value }} | ||
| - name: Upload CLI packages as workflow artifact | ||
| if: ${{ needs.prepare_release.outputs.should_publish != 'true' }} | ||
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | ||
| with: | ||
| name: release-linux-cli-x86_64-${{ steps.get-config.outputs.channel }} | ||
| path: | | ||
| ${{ steps.bundle_cli.outputs.packages_dir }} | ||
| oz-${{ steps.get-config.outputs.channel }}-linux-x86_64.tar.gz | ||
| build_linux_arm_binaries: | ||
| name: Build Release (Linux ARM) | ||
| runs-on: namespace-profile-ubuntu-20-04-arm | ||
| needs: prepare_release | ||
| if: ${{ inputs.build_linux != false }} | ||
| timeout-minutes: 90 | ||
| env: | ||
| # Automatically extract AppImages before running them instead of mounting | ||
| # them with FUSE, which isn't available on GitHub runners (and this is | ||
| # easier and less error-prone than trying to install it). | ||
| APPIMAGE_EXTRACT_AND_RUN: "1" | ||
| # Cache the generated settings schema so prepare_bundled_resources only | ||
| # compiles and runs the generator once per job instead of per-package. | ||
| SETTINGS_SCHEMA_CACHE: ${{ github.workspace }}/.settings_schema_cache.json | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| - uses: ./.github/actions/prepare_environment | ||
| with: | ||
| target_os: linux | ||
| is_self_hosted: false | ||
| ref: ${{ needs.prepare_release.outputs.release_branch }} | ||
| install_release_deps: true | ||
| ssh_key: ${{ secrets.WARP_CHANNEL_CONFIG_ACCESS_SSH_KEY }} | ||
| # Install gcc 10, as gcc 9.5 has a bug with memcmp that is incompatible | ||
| # with aws-lc-rs (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95189). | ||
| - name: Install and configure gcc-10 | ||
| run: | | ||
| sudo apt update | ||
| sudo apt install -y gcc-10 g++-10 | ||
| sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 60 --slave /usr/bin/g++ g++ /usr/bin/g++-10 | ||
| gcc --version | ||
| g++ --version | ||
| - name: Update path | ||
| run: | | ||
| # Exports .local/bin into the path for subsequent runs. | ||
| # We need this for the linuxdeploy install and bundle steps, | ||
| # as the linuxdeploy appimage is installed to $HOME/local/bin. | ||
| if [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then | ||
| echo "Adding $HOME/.local/bin to PATH" | ||
| echo "$HOME/.local/bin" >> $GITHUB_PATH | ||
| fi | ||
| shell: bash | ||
| - name: Get channel configuration | ||
| id: get-config | ||
| uses: ./.github/actions/get_channel_config/ | ||
| with: | ||
| config_file: ${{ env.CONFIG_FILE }} | ||
| channel: ${{ inputs.channel }} | ||
| - uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 | ||
| with: | ||
| credentials_json: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} | ||
| - name: Install linuxdeploy | ||
| run: script/linux/install_linuxdeploy | ||
| # Namespace's User Bundled Cache persists target/ between jobs on the same profile, which can | ||
| # leave stale packages from a previous channel's build in the linux bundle output dir. | ||
| - name: Clean stale bundle output | ||
| run: rm -rf target/*/bundle/linux | ||
| shell: bash | ||
| - name: Build app | ||
| id: build_app | ||
| run: | | ||
| # Build the code, but only bundle the appimage | ||
| script/bundle --channel $CHANNEL --packages appimage | ||
| shell: bash | ||
| env: | ||
| CHANNEL: ${{ steps.get-config.outputs.channel }} | ||
| GIT_RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }} | ||
| - name: Package binaries | ||
| id: package_binaries | ||
| run: | | ||
| # Tar up all the binaries we need for the next stage | ||
| EXECUTABLE_PATH="$(realpath --relative-to=$(pwd) $EXECUTABLE_PATH)" | ||
| DEBUG_EXECUTABLE_PATH="$(realpath --relative-to=$(pwd) $DEBUG_EXECUTABLE_PATH)" | ||
| PACKAGES_DIR="$(realpath --relative-to=$(pwd) $PACKAGES_DIR)" | ||
| tar czvf binaries.tar.gz $EXECUTABLE_PATH $DEBUG_EXECUTABLE_PATH $PACKAGES_DIR | ||
| shell: bash | ||
| env: | ||
| EXECUTABLE_PATH: ${{ steps.build_app.outputs.executable_path }} | ||
| DEBUG_EXECUTABLE_PATH: ${{ steps.build_app.outputs.debug_executable_path }} | ||
| PACKAGES_DIR: ${{steps.build_app.outputs.packages_dir}} | ||
| - name: Archive build files | ||
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | ||
| with: | ||
| name: built-arm64-linux-${{steps.get-config.outputs.channel}} | ||
| retention-days: 1 | ||
| path: binaries.tar.gz | ||
| build_linux_cli_arm_binaries: | ||
| name: Build Release (Linux CLI ARM) | ||
| runs-on: namespace-profile-ubuntu-20-04-arm | ||
| needs: prepare_release | ||
| if: ${{ inputs.build_linux != false }} | ||
| timeout-minutes: 90 | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| - uses: ./.github/actions/prepare_environment | ||
| with: | ||
| target_os: linux | ||
| is_self_hosted: false | ||
| ref: ${{ needs.prepare_release.outputs.release_branch }} | ||
| install_release_deps: true | ||
| ssh_key: ${{ secrets.WARP_CHANNEL_CONFIG_ACCESS_SSH_KEY }} | ||
| # Install gcc 10, as gcc 9.5 has a bug with memcmp that is incompatible | ||
| # with aws-lc-rs (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95189). | ||
| - name: Install and configure gcc-10 | ||
| run: | | ||
| sudo apt update | ||
| sudo apt install -y gcc-10 g++-10 | ||
| sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 60 --slave /usr/bin/g++ g++ /usr/bin/g++-10 | ||
| gcc --version | ||
| g++ --version | ||
| - name: Get channel configuration | ||
| id: get-config | ||
| uses: ./.github/actions/get_channel_config/ | ||
| with: | ||
| config_file: ${{ env.CONFIG_FILE }} | ||
| channel: ${{ inputs.channel }} | ||
| - uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 | ||
| with: | ||
| credentials_json: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} | ||
| # Namespace's User Bundled Cache persists target/ between jobs on the same profile, which can | ||
| # leave stale packages from a previous channel's build in the linux bundle output dir. | ||
| - name: Clean stale bundle output | ||
| run: rm -rf target/*/bundle/linux | ||
| shell: bash | ||
| - name: Build CLI | ||
| id: build_cli | ||
| run: | | ||
| # Build the CLI only | ||
| script/bundle --channel $CHANNEL --artifact cli --packages none | ||
| shell: bash | ||
| env: | ||
| CHANNEL: ${{ steps.get-config.outputs.channel }} | ||
| GIT_RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }} | ||
| - name: Package binaries | ||
| id: package_binaries | ||
| run: | | ||
| # Tar up all the binaries we need for the next stage | ||
| EXECUTABLE_PATH="$(realpath --relative-to=$(pwd) $EXECUTABLE_PATH)" | ||
| DEBUG_EXECUTABLE_PATH="$(realpath --relative-to=$(pwd) $DEBUG_EXECUTABLE_PATH)" | ||
| PACKAGES_DIR="$(realpath --relative-to=$(pwd) $PACKAGES_DIR)" | ||
| tar czvf binaries-cli.tar.gz $EXECUTABLE_PATH $DEBUG_EXECUTABLE_PATH $PACKAGES_DIR | ||
| shell: bash | ||
| env: | ||
| EXECUTABLE_PATH: ${{ steps.build_cli.outputs.executable_path }} | ||
| DEBUG_EXECUTABLE_PATH: ${{ steps.build_cli.outputs.debug_executable_path }} | ||
| PACKAGES_DIR: ${{steps.build_cli.outputs.packages_dir}} | ||
| - name: Archive build files | ||
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | ||
| with: | ||
| name: built-arm64-linux-cli-${{steps.get-config.outputs.channel}} | ||
| retention-days: 1 | ||
| path: binaries-cli.tar.gz | ||
| # This is done as a separate job from `build_linux_arm_binaries` and `build_linux_cli_arm_binaries` | ||
| # because the steps here were hard to get running on the self-hosted runners. | ||
| release_linux_arm: | ||
| name: Bundle Release (Linux ARM) | ||
| runs-on: namespace-profile-ubuntu-20-04 | ||
| needs: [ prepare_release, build_linux_arm_binaries, build_linux_cli_arm_binaries ] | ||
| if: ${{ inputs.build_linux != false }} | ||
| timeout-minutes: 60 | ||
| env: | ||
| # Cache the generated settings schema so prepare_bundled_resources only | ||
| # compiles and runs the generator once per job instead of per-package. | ||
| SETTINGS_SCHEMA_CACHE: ${{ github.workspace }}/.settings_schema_cache.json | ||
| steps: | ||
| - name: Checkout sources | ||
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| with: | ||
| ref: ${{ needs.prepare_release.outputs.release_branch }} | ||
| - name: Get channel configuration | ||
| id: get-config | ||
| uses: ./.github/actions/get_channel_config/ | ||
| with: | ||
| config_file: ${{ env.CONFIG_FILE }} | ||
| channel: ${{ inputs.channel }} | ||
| - uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 | ||
| with: | ||
| credentials_json: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} | ||
| - name: Set up Sentry CLI | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b # v2.0.0 | ||
| with: | ||
| token: ${{ secrets.SENTRY_RELEASE_TOKEN }} | ||
| organization: warpdotdev | ||
| project: ${{ steps.get-config.outputs.sentry_project }} | ||
| # Install gcc 10, as gcc 9.5 has a bug with memcmp that is incompatible | ||
| # with aws-lc-rs (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95189). | ||
| - name: Install and configure gcc-10 | ||
| run: | | ||
| sudo apt update | ||
| sudo apt install -y gcc-10 g++-10 | ||
| sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 60 --slave /usr/bin/g++ g++ /usr/bin/g++-10 | ||
| gcc --version | ||
| g++ --version | ||
| # Install Linux build dependencies (protoc, libssl-dev, etc.). Although this job | ||
| # runs with --skip-build, script/prepare_bundled_resources still invokes | ||
| # `cargo run --bin generate_settings_schema` and `cargo about generate`, which | ||
| # compile workspace crates whose build scripts depend on protoc and other | ||
| # system libraries. The four sibling Linux jobs get these via prepare_environment; | ||
| # this job doesn't use prepare_environment, so install them explicitly here. | ||
| - name: Install Linux build dependencies | ||
| shell: bash | ||
| run: ./script/linux/install_build_deps | ||
| - name: Install release dependencies | ||
| shell: bash | ||
| run: | | ||
| ./script/install_cargo_release_deps --no-build-deps | ||
| - name: Load PGP signing key and passphrase | ||
| run: | | ||
| mkdir -p ~/.gnupg | ||
| echo "default-cache-ttl 7200" >> ~/.gnupg/gpg-agent.conf | ||
| # Set the appropriate permissions for files and directories. | ||
| find ~/.gnupg -type f -exec chmod 600 {} \; | ||
| find ~/.gnupg -type d -exec chmod 700 {} \; | ||
| # Test the agent configuration. This is helpful for debugging if | ||
| # something is invalid. | ||
| gpgconf --check-options gpg-agent | ||
| gpg-agent --gpgconf-test | ||
| # Kill the agent, if one is running, and then start a new one - this | ||
| # ensures our updated configuration is applied correctly. | ||
| gpgconf --kill gpg-agent | ||
| gpgconf --launch gpg-agent | ||
| # Retrieve our signing key and import it into gpg. | ||
| gcloud --project astral-field-294621 secrets versions access latest --secret=linux-releases-pgp-key | gpg --batch --import | ||
| # Populate the passphrase for our signing key in the gpg-agent cache. | ||
| # by signing an empty file. | ||
| touch emptyfile | ||
| gpg --no-tty --pinentry-mode loopback --passphrase-fd 0 --detach-sign --armor --batch --yes --output emptyfile.sig emptyfile << EOF | ||
| ${{ secrets.LINUX_RELEASES_PGP_KEY_PASSPHRASE }} | ||
| EOF | ||
| rm emptyfile.sig | ||
| echo "Populated gpg-agent cache" | ||
| shell: bash | ||
| # Bundle the app packages | ||
| # Namespace's User Bundled Cache persists target/ between jobs on the same profile, which can | ||
| # leave stale packages from a previous channel's build in the linux bundle output dir. | ||
| - name: Clean stale bundle output | ||
| run: rm -rf target/*/bundle/linux | ||
| shell: bash | ||
| - name: Download app build artifacts | ||
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | ||
| with: | ||
| name: built-arm64-linux-${{steps.get-config.outputs.channel}} | ||
| - name: Unpackage app binaries | ||
| id: unpackage_app_binaries | ||
| run: | | ||
| tar xzvf binaries.tar.gz | ||
| shell: bash | ||
| - name: Bundle deb/rpm app packages | ||
| id: bundle_app | ||
| run: | | ||
| # Bundle everything but the arch package, as we need to bundle it | ||
| # within a Docker container. | ||
| script/bundle --channel $CHANNEL --skip-build --packages deb,rpm --arch aarch64 | ||
| shell: bash | ||
| env: | ||
| CHANNEL: ${{ steps.get-config.outputs.channel }} | ||
| GIT_RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }} | ||
| - name: Bundle Arch Linux app package | ||
| uses: ./.github/actions/bundle_arch_package | ||
| with: | ||
| channel: ${{ steps.get-config.outputs.channel }} | ||
| release-tag: ${{ needs.prepare_release.outputs.release_tag }} | ||
| arch: aarch64 | ||
| - name: Upload app debugging symbols to Sentry | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| # Important: we have to do this before the binary is overwritten by the CLI version, which has the same filename | ||
| run: | | ||
| script/sentry_upload_dif.sh | ||
| env: | ||
| DEBUG_FILE_OR_FOLDER_PATH: ${{ steps.bundle_app.outputs.debug_executable_path }} | ||
| shell: bash | ||
| # Bundle the CLI packages | ||
| - name: Download CLI build artifacts | ||
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | ||
| with: | ||
| name: built-arm64-linux-cli-${{steps.get-config.outputs.channel}} | ||
| - name: Unpackage CLI binaries | ||
| id: unpackage_cli_binaries | ||
| run: | | ||
| tar xzvf binaries-cli.tar.gz | ||
| shell: bash | ||
| - name: Bundle deb/rpm CLI packages | ||
| id: bundle_cli | ||
| run: | | ||
| script/bundle --channel $CHANNEL --skip-build --arch aarch64 --packages deb,rpm --artifact cli | ||
| shell: bash | ||
| env: | ||
| CHANNEL: ${{ steps.get-config.outputs.channel }} | ||
| GIT_RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }} | ||
| - name: Package CLI tar.gz | ||
| run: | | ||
| cp ${{ steps.bundle_cli.outputs.executable_path }} oz-${{ steps.get-config.outputs.channel }} | ||
| tar czf oz-${{ steps.get-config.outputs.channel }}-linux-aarch64.tar.gz oz-${{ steps.get-config.outputs.channel }} -C "$(dirname "${{ steps.bundle_cli.outputs.bundled_resources_dir }}")" resources | ||
| - name: Bundle Arch Linux CLI package | ||
| uses: ./.github/actions/bundle_arch_package | ||
| with: | ||
| channel: ${{ steps.get-config.outputs.channel }} | ||
| release-tag: ${{ needs.prepare_release.outputs.release_tag }} | ||
| arch: aarch64 | ||
| artifact: cli | ||
| - name: Upload CLI debugging symbols to Sentry | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| run: | | ||
| script/sentry_upload_dif.sh | ||
| env: | ||
| DEBUG_FILE_OR_FOLDER_PATH: ${{ steps.bundle_cli.outputs.debug_executable_path }} | ||
| shell: bash | ||
| # Common uploading steps | ||
| - name: Sign Arch Linux packages | ||
| run: | | ||
| # We technically only need to run `sign_arch_packages` once, as $APP_PKGDIR and $CLI_PKGDIR should be the same. | ||
| ./script/linux/sign_arch_packages "$APP_PKGDIR" | ||
| ./script/linux/sign_arch_packages "$CLI_PKGDIR" | ||
| shell: bash | ||
| env: | ||
| APP_PKGDIR: ${{ steps.bundle_app.outputs.packages_dir }} | ||
| CLI_PKGDIR: ${{ steps.bundle_cli.outputs.packages_dir }} | ||
| - name: Add app packages to GitHub release assets | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 | ||
| with: | ||
| tag_name: ${{ needs.prepare_release.outputs.release_tag }} | ||
| files: ${{ steps.bundle_app.outputs.packages_dir }}/* | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Add CLI packages to GitHub release assets | ||
| uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' && steps.bundle_cli.outputs.packages_dir != steps.bundle_app.outputs.packages_dir }} | ||
| with: | ||
| tag_name: ${{ needs.prepare_release.outputs.release_tag }} | ||
| files: ${{ steps.bundle_cli.outputs.packages_dir }}/* | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Add CLI tar.gz to GitHub release assets | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 | ||
| with: | ||
| tag_name: ${{ needs.prepare_release.outputs.release_tag }} | ||
| files: oz-${{ steps.get-config.outputs.channel }}-linux-aarch64.tar.gz | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Upload app packages to Google Cloud Storage | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: google-github-actions/upload-cloud-storage@e95a15f226403ed658d3e65f40205649f342ba2c # v1 | ||
| with: | ||
| path: ${{ steps.bundle_app.outputs.packages_dir }} | ||
| parent: false | ||
| destination: warp-releases/${{ steps.get-config.outputs.channel }}/${{ needs.prepare_release.outputs.release_tag }} | ||
| # IMPORTANT: both the key and value of the cache-control header must be all lowercase; | ||
| # uppercase values will not be respected by Cloud CDN and using "Cache-Control" will be | ||
| # ignored by the upload-cloud-storage action. | ||
| headers: |- | ||
| cache-control: ${{ steps.get-config.outputs.gcs_cache_control_value }} | ||
| - name: Upload CLI packages to Google Cloud Storage | ||
| uses: google-github-actions/upload-cloud-storage@e95a15f226403ed658d3e65f40205649f342ba2c # v1 | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' && steps.bundle_cli.outputs.packages_dir != steps.bundle_app.outputs.packages_dir }} | ||
| with: | ||
| path: ${{ steps.bundle_cli.outputs.packages_dir }} | ||
| parent: false | ||
| destination: warp-releases/${{ steps.get-config.outputs.channel }}/${{ needs.prepare_release.outputs.release_tag }} | ||
| # IMPORTANT: both the key and value of the cache-control header must be all lowercase; | ||
| # uppercase values will not be respected by Cloud CDN and using "Cache-Control" will be | ||
| # ignored by the upload-cloud-storage action. | ||
| headers: |- | ||
| cache-control: ${{ steps.get-config.outputs.gcs_cache_control_value }} | ||
| - name: Upload CLI tar.gz to Google Cloud Storage | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: google-github-actions/upload-cloud-storage@e95a15f226403ed658d3e65f40205649f342ba2c # v1 | ||
| with: | ||
| path: oz-${{ steps.get-config.outputs.channel }}-linux-aarch64.tar.gz | ||
| destination: warp-releases/${{ steps.get-config.outputs.channel }}/${{ needs.prepare_release.outputs.release_tag }}/cli/linux/aarch64 | ||
| headers: |- | ||
| cache-control: ${{ steps.get-config.outputs.gcs_cache_control_value }} | ||
| - name: Upload packages as workflow artifact | ||
| if: ${{ needs.prepare_release.outputs.should_publish != 'true' }} | ||
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | ||
| with: | ||
| name: release-linux-arm64-${{ steps.get-config.outputs.channel }} | ||
| path: | | ||
| ${{ steps.bundle_app.outputs.packages_dir }} | ||
| oz-${{ steps.get-config.outputs.channel }}-linux-aarch64.tar.gz | ||
| release_web: | ||
| name: Build Release (Web) | ||
| runs-on: namespace-profile-ubuntu-22-04 | ||
| needs: prepare_release | ||
| if: ${{ inputs.build_web != false }} | ||
| timeout-minutes: 60 | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| - uses: ./.github/actions/prepare_environment | ||
| with: | ||
| target_os: wasm | ||
| is_self_hosted: false | ||
| ref: ${{ needs.prepare_release.outputs.release_branch }} | ||
| ssh_key: ${{ secrets.WARP_CHANNEL_CONFIG_ACCESS_SSH_KEY }} | ||
| - name: Get channel configuration | ||
| id: get-config | ||
| uses: ./.github/actions/get_channel_config/ | ||
| with: | ||
| config_file: ${{ env.CONFIG_FILE }} | ||
| channel: ${{ inputs.channel }} | ||
| - name: Bundle app | ||
| id: bundle_app | ||
| run: | | ||
| script/wasm/bundle --channel $CHANNEL | ||
| shell: bash | ||
| env: | ||
| CHANNEL: ${{ steps.get-config.outputs.channel }} | ||
| GIT_RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }} | ||
| - name: Brotli compress app bundle | ||
| run: | | ||
| # The brotli binary won't let us compress in-place, so we need to rename back to the | ||
| # original afterwards. | ||
| brotli --rm "${{ steps.bundle_app.outputs.packages_dir }}"/* | ||
| for file in "${{ steps.bundle_app.outputs.packages_dir }}"/*.br; do | ||
| mv -- "$file" "${file%.br}" | ||
| done | ||
| shell: bash | ||
| - name: Set up Sentry CLI | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b # v2.0.0 | ||
| with: | ||
| token: ${{ secrets.SENTRY_RELEASE_TOKEN }} | ||
| organization: warpdotdev | ||
| project: ${{ steps.get-config.outputs.sentry_project }} | ||
| - name: Upload debugging symbols to Sentry | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| run: | | ||
| script/sentry_upload_dif.sh | ||
| shell: bash | ||
| env: | ||
| DEBUG_FILE_OR_FOLDER_PATH: ${{ steps.bundle_app.outputs.debug_executable_path }} | ||
| - name: Add packages to GitHub release assets | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| id: upload_github_assets | ||
| uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 | ||
| with: | ||
| tag_name: ${{ needs.prepare_release.outputs.release_tag }} | ||
| files: ${{ steps.bundle_app.outputs.packages_dir }}/* | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| with: | ||
| credentials_json: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} | ||
| - name: Upload packages to Google Cloud Storage | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: google-github-actions/upload-cloud-storage@e95a15f226403ed658d3e65f40205649f342ba2c # v1 | ||
| with: | ||
| path: ${{ steps.bundle_app.outputs.packages_dir }} | ||
| # Only upload the files from within `packages_dir`, don't include the | ||
| # (parent) folder itself. | ||
| gzip: false | ||
| parent: false | ||
| destination: ${{ steps.get-config.outputs.web_gcs_bucket_prefix }}-releases/${{ steps.get-config.outputs.channel }}/${{ needs.prepare_release.outputs.release_tag }} | ||
| # IMPORTANT: both the key and value of the cache-control header must be all lowercase; | ||
| # uppercase values will not be respected by Cloud CDN and using "Cache-Control" will be | ||
| # ignored by the upload-cloud-storage action. | ||
| headers: |- | ||
| cache-control: ${{ steps.get-config.outputs.gcs_cache_control_value }} | ||
| content-encoding: br | ||
| - name: Upload assets to Google Cloud Storage | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: google-github-actions/upload-cloud-storage@e95a15f226403ed658d3e65f40205649f342ba2c # v1 | ||
| with: | ||
| path: ${{ steps.bundle_app.outputs.assets_dir }} | ||
| parent: false | ||
| # All asset filenames contain the file hash for cashing purposes, so we store them all in | ||
| # one directory so they can be cached across releases. | ||
| destination: ${{ steps.get-config.outputs.web_gcs_bucket_prefix }}-static-assets/ | ||
| # IMPORTANT: both the key and value of the cache-control header must be all lowercase; | ||
| # uppercase values will not be respected by Cloud CDN and using "Cache-Control" will be | ||
| # ignored by the upload-cloud-storage action. | ||
| # These assets are all stored under cache busting names, so we want to cache them | ||
| # effectively forever. There's no defined maximum for the max-age directive, but a similar | ||
| # directive suggests a maximum of one year, so that's what's chosen here. | ||
| headers: |- | ||
| cache-control: private, max-age=31536000, immutable | ||
| - name: Upload web bundle as workflow artifact | ||
| if: ${{ needs.prepare_release.outputs.should_publish != 'true' }} | ||
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | ||
| with: | ||
| name: release-web-${{ steps.get-config.outputs.channel }} | ||
| path: ${{ steps.bundle_app.outputs.packages_dir }} | ||
| release_windows: | ||
| name: Build Release (Windows ${{ matrix.arch }}) | ||
| runs-on: ${{ matrix.runner }} | ||
| needs: prepare_release | ||
| if: ${{ inputs.build_windows != false }} | ||
| timeout-minutes: 150 | ||
| strategy: | ||
| matrix: | ||
| include: | ||
| - arch: x64 | ||
| runner: windows-latest-large | ||
| - arch: arm64 | ||
| runner: windows-latest-large | ||
| env: | ||
| TRUSTED_SIGNING_ENDPOINT: https://eus.codesigning.azure.net/ | ||
| TRUSTED_SIGNING_ACCOUNT: warpdotdev | ||
| TRUSTED_SIGNING_CERT_PROFILE: warpterminal | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| - uses: ./.github/actions/prepare_environment | ||
| with: | ||
| target_os: windows | ||
| cache_key: ${{ matrix.arch }} | ||
| is_self_hosted: false | ||
| ref: ${{ needs.prepare_release.outputs.release_branch }} | ||
| install_release_deps: true | ||
| ssh_key: ${{ secrets.WARP_CHANNEL_CONFIG_ACCESS_SSH_KEY }} | ||
| - name: Add arm64 target | ||
| if: ${{ matrix.arch == 'arm64' }} | ||
| run: rustup target add aarch64-pc-windows-msvc | ||
| shell: bash | ||
| - name: Get channel configuration | ||
| id: get-config | ||
| uses: ./.github/actions/get_channel_config/ | ||
| with: | ||
| config_file: ${{ env.CONFIG_FILE }} | ||
| channel: ${{ inputs.channel }} | ||
| - name: Build binary | ||
| id: build_binary | ||
| run: script/bundle -Channel $CHANNEL -skip_build_installer --arch ${{ matrix.arch }} | ||
| shell: bash | ||
| env: | ||
| CHANNEL: ${{ steps.get-config.outputs.channel }} | ||
| GIT_RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }} | ||
| - name: Sign the executables with Azure Trusted Signing | ||
| uses: azure/artifact-signing-action@b443cf8ea4124818d2ea9f043cba29fc3ec47b16 # v1.2.0 | ||
| with: | ||
| azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }} | ||
| azure-client-id: ${{ secrets.AZURE_CLIENT_ID }} | ||
| azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} | ||
| endpoint: ${{ env.TRUSTED_SIGNING_ENDPOINT }} | ||
| trusted-signing-account-name: ${{ env.TRUSTED_SIGNING_ACCOUNT }} | ||
| certificate-profile-name: ${{ env.TRUSTED_SIGNING_CERT_PROFILE }} | ||
| files: | | ||
| ${{ steps.build_binary.outputs.binary_path }} | ||
| ${{ github.workspace }}\app\assets\bundled\bootstrap\pwsh.ps1 | ||
| files-folder: ${{ github.workspace }}\app\assets\windows\${{ matrix.arch }} | ||
| files-folder-filter: dll,exe | ||
| files-folder-recurse: true | ||
| files-folder-depth: 2 | ||
| file-digest: SHA256 | ||
| timestamp-rfc3161: http://timestamp.acs.microsoft.com | ||
| timestamp-digest: SHA256 | ||
| # The azure/artifact-signing-action above downloads signtool.exe and the Trusted Signing dlib. | ||
| # We locate them so ISCC can call signtool during compilation to sign the inner setup engine | ||
| # (the file extracted to %TEMP% at runtime). This prevents Defender ASR rule D4F940AB from | ||
| # blocking the installer in enterprise environments. See this issue: | ||
| # https://github.com/warpdotdev/Warp/issues/8794 | ||
| - name: Build sign-tool command for Inno Setup | ||
| id: setup_signing | ||
| shell: pwsh | ||
| run: | | ||
| $Dlib = (Get-ChildItem -Recurse "$env:LOCALAPPDATA" -Filter "Azure.CodeSigning.Dlib.dll" -ErrorAction SilentlyContinue | | ||
| Where-Object { $_.FullName -match 'x64' } | Select-Object -First 1).FullName | ||
| if (-not $Dlib) { throw "Azure.CodeSigning.Dlib.dll not found — did the earlier signing action run?" } | ||
| Write-Output "Dlib: $Dlib" | ||
| $SignTool = (Get-ChildItem -Recurse "C:\Program Files (x86)\Windows Kits" -Filter "signtool.exe" | | ||
| Where-Object { $_.FullName -match 'x64' } | Sort-Object FullName -Descending | Select-Object -First 1).FullName | ||
| if (-not $SignTool) { throw "signtool.exe not found in Windows SDK" } | ||
| Write-Output "SignTool: $SignTool" | ||
| # Add signtool's directory to PATH so the ISCC sign command can reference it as just "signtool.exe". | ||
| # Embedded quotes in the /Scodesign= value break PowerShell's native-command argument passing to ISCC. | ||
| (Split-Path $SignTool) >> $env:GITHUB_PATH | ||
| $MetadataPath = "${{ runner.temp }}\tsc-metadata.json" | ||
| @{Endpoint=$env:TRUSTED_SIGNING_ENDPOINT;CodeSigningAccountName=$env:TRUSTED_SIGNING_ACCOUNT;CertificateProfileName=$env:TRUSTED_SIGNING_CERT_PROFILE} | | ||
| ConvertTo-Json | Set-Content $MetadataPath | ||
| "sign_tool_cmd=signtool.exe sign /v /fd SHA256 /tr http://timestamp.acs.microsoft.com /td SHA256 /dlib $Dlib /dmdf $MetadataPath `$f" >> $env:GITHUB_OUTPUT | ||
| - name: Bundle app | ||
| id: bundle_app | ||
| run: script/bundle -Channel $CHANNEL -skip_build_binary --arch ${{ matrix.arch }} | ||
| shell: bash | ||
| env: | ||
| CHANNEL: ${{ steps.get-config.outputs.channel }} | ||
| GIT_RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }} | ||
| AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} | ||
| AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} | ||
| AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} | ||
| SIGN_TOOL_CMD: ${{ steps.setup_signing.outputs.sign_tool_cmd }} | ||
| - name: Set up Sentry CLI | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b # v2.0.0 | ||
| with: | ||
| token: ${{ secrets.SENTRY_RELEASE_TOKEN }} | ||
| organization: warpdotdev | ||
| project: ${{ steps.get-config.outputs.sentry_project }} | ||
| - name: Upload binary to Sentry | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| run: | | ||
| script/sentry_upload_dif.sh | ||
| shell: bash | ||
| env: | ||
| DEBUG_FILE_OR_FOLDER_PATH: ${{ steps.build_binary.outputs.binary_path }} | ||
| - name: Upload debugging symbols to Sentry | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| run: | | ||
| script/sentry_upload_dif.sh | ||
| shell: bash | ||
| env: | ||
| DEBUG_FILE_OR_FOLDER_PATH: ${{ steps.bundle_app.outputs.pdb_file_path }} | ||
| - name: Add installer to GitHub release assets | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| id: upload_github_assets | ||
| uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 | ||
| with: | ||
| tag_name: ${{ needs.prepare_release.outputs.release_tag }} | ||
| files: ${{ steps.bundle_app.outputs.installer_path }} | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| with: | ||
| credentials_json: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} | ||
| - name: Upload installer to Google Cloud Storage | ||
| if: ${{ needs.prepare_release.outputs.should_publish == 'true' }} | ||
| uses: google-github-actions/upload-cloud-storage@e95a15f226403ed658d3e65f40205649f342ba2c # v1 | ||
| with: | ||
| path: ${{ steps.bundle_app.outputs.installer_path }} | ||
| destination: warp-releases/${{ steps.get-config.outputs.channel }}/${{ needs.prepare_release.outputs.release_tag }} | ||
| # IMPORTANT: both the key and value of the cache-control header must be all lowercase; | ||
| # uppercase values will not be respected by Cloud CDN and using "Cache-Control" will be | ||
| # ignored by the upload-cloud-storage action. | ||
| headers: |- | ||
| cache-control: ${{ steps.get-config.outputs.gcs_cache_control_value }} | ||
| - name: Upload installer as workflow artifact | ||
| if: ${{ needs.prepare_release.outputs.should_publish != 'true' }} | ||
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | ||
| with: | ||
| name: release-windows-${{ matrix.arch }}-${{ steps.get-config.outputs.channel }} | ||
| path: ${{ steps.bundle_app.outputs.installer_path }} | ||
| DISABLED_send_slack_notif_if_unsuccessful: | ||
| name: Send Slack notification if any release jobs were unsuccessful | ||
| runs-on: ubuntu-latest | ||
| needs: | ||
| - prepare_release | ||
| if: false | ||
| steps: | ||
| - name: Figure out which releases failed, if any | ||
| id: failed_releases | ||
| shell: bash | ||
| run: | | ||
| FAILED=() | ||
| if [[ ${{ needs.release_macos_single_arch.result }} != 'success' ]]; then | ||
| FAILED+=("MacOS Single Arch") | ||
| fi | ||
| if [[ ${{ needs.release_macos_universal.result }} != 'success' ]]; then | ||
| FAILED+=("MacOS Universal") | ||
| fi | ||
| if [[ ${{ needs.release_macos_cli.result }} != 'success' ]]; then | ||
| FAILED+=('MacOS CLI') | ||
| fi | ||
| if [[ ${{ needs.release_linux_x86.result }} != 'success' ]]; then | ||
| FAILED+=("Linux x86_64") | ||
| fi | ||
| if [[ ${{ needs.release_linux_arm.result }} != 'success' ]]; then | ||
| FAILED+=("Linux ARM64") | ||
| fi | ||
| if [[ ${{ needs.release_linux_cli_x86.result }} != 'success' ]]; then | ||
| FAILED+=("Linux CLI x86_64") | ||
| fi | ||
| if [[ ${{ needs.release_web.result }} != 'success' && ${{ inputs.channel }} != 'preview' ]]; then | ||
| FAILED+=("WASM") | ||
| fi | ||
| if [[ ${{ needs.release_windows.result }} != 'success' ]]; then | ||
| FAILED+=("Windows") | ||
| fi | ||
| if (( ${#FAILED[@]} )); then | ||
| printf -v FORMATTED "%s, " "${FAILED[@]}" | ||
| echo "failed=$(echo "{${FORMATTED%, }}")" >> $GITHUB_OUTPUT | ||
| fi | ||
| - name: Send Slack notification if unsuccessful | ||
| uses: slackapi/slack-github-action@410ae57cff5c6b682b106440be0e6c7eb8c98c9d # v1.16.0 | ||
| if: ${{ steps.failed_releases.outputs.failed != '' }} | ||
| with: | ||
| channel-id: "#oncall-client" | ||
| # Follows https://api.slack.com/reference/surfaces/formatting#mentioning-users. | ||
| # S06N82RS7FA is the user group ID for @oncall-client-eng. | ||
| slack-message: "Failed to create ${{ steps.failed_releases.outputs.failed }} release artifacts for ${{ inputs.channel }}. See https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}. cc: <!subteam^S06N82RS7FA>" | ||
| env: | ||
| SLACK_BOT_TOKEN: ${{ secrets.ACTION_MONITORING_SLACK }} | ||
| generate_changelogs: | ||
| name: Generate Changelogs | ||
| # TEMPORARY: removed should_publish and build job deps for isolated test | ||
| runs-on: ubuntu-latest | ||
| needs: | ||
| - prepare_release | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| name: Checkout sources | ||
| with: | ||
| # Fetch history for all tags and branches so we can compare revisions | ||
| # in order to generate the changelog. | ||
| fetch-depth: 0 | ||
| - name: Get channel configuration | ||
| id: get-config | ||
| uses: ./.github/actions/get_channel_config/ | ||
| with: | ||
| config_file: ${{ env.CONFIG_FILE }} | ||
| channel: ${{ inputs.channel }} | ||
| - name: Generate changelog via Oz | ||
| uses: warpdotdev/oz-agent-action@ce1621abf6a8ed8afdd4e4cc994545ede8fe1c6f # main | ||
| with: | ||
| prompt: | | ||
| Generate a changelog draft for the stable channel, release tag v0.2026.05.13.09.14.stable_00. | ||
| Output directory: ${{ runner.temp }}/changelog-draft | ||
| Follow the workflow in .agents/skills/changelog-draft/SKILL.md exactly. | ||
| Make sure to produce both output files: changelog-draft.md and changelog-draft.json. | ||
| After writing the output files, print the full contents of changelog-draft.md to stdout so it appears in the workflow log. | ||
| You are running in a GitHub Actions workflow. The repo is checked out at the default branch (HEAD) with full history. Use the release_tag input as the git range endpoint — do NOT check out the release tag. `gh` is authenticated. Do not commit, push, or create PRs. | ||
| warp_api_key: ${{ secrets.WARP_API_KEY }} | ||
| share: team | ||
| - name: Convert draft JSON to release format | ||
| shell: bash | ||
| run: | | ||
| python3 .agents/skills/changelog-draft/scripts/convert_to_release_json.py \ | ||
| --input "${{ runner.temp }}/changelog-draft/changelog-draft.json" \ | ||
| --output "${{ runner.temp }}/changelog-draft/changelog-release.json" | ||
| - name: Load release changelog into step output | ||
| id: generate_changelog | ||
| shell: bash | ||
| run: | | ||
| # Read the release-pipeline-compatible JSON produced by the conversion | ||
| # script and expose it as a step output so downstream steps can consume | ||
| # it with the same interface as the old generate-changelog action. | ||
| CHANGELOG_FILE="${{ runner.temp }}/changelog-draft/changelog-release.json" | ||
| if [ ! -f "$CHANGELOG_FILE" ]; then | ||
| echo "::error::changelog-release.json not found at $CHANGELOG_FILE" | ||
| exit 1 | ||
| fi | ||
| # Validate JSON | ||
| jq empty "$CHANGELOG_FILE" | ||
| # Set multiline output | ||
| echo "changelog<<CHANGELOG_EOF" >> $GITHUB_OUTPUT | ||
| cat "$CHANGELOG_FILE" >> $GITHUB_OUTPUT | ||
| echo "CHANGELOG_EOF" >> $GITHUB_OUTPUT | ||
| - name: Build Slack changelog payload | ||
| id: build_slack_payload | ||
| shell: bash | ||
| env: | ||
| CHANGELOG_MD: ${{ steps.generate_changelog.outputs.changelog }} | ||
| RELEASE_TAG: v0.2026.05.13.09.14.stable_00 | ||
| run: | | ||
| # Rename the keys in the Changelog JSON to something more human readable. | ||
| # This is the changelog that goes to slack so it doesn't need to be extremely filtered. | ||
| NEW_CHANGELOG=$(echo $CHANGELOG_MD | jq 'with_entries(if .key == "newFeatures" then .key = "New Features" else . end)' | jq 'with_entries(if .key == "improvements" then .key = "Improvements" else . end)' | jq 'with_entries(if .key == "bugFixes" then .key = "Bug Fixes" else . end)' | jq 'with_entries(if .key == "images" then .key = "Image" else . end)') | ||
| # Generate the full markdown text as individual lines. | ||
| MARKDOWN=$(echo "$NEW_CHANGELOG" | jq -r 'to_entries[] | select(.value | length > 0) | "*\(.key)*", (.value[] | " \u2022 \(.)")') | ||
| if [ -z "$MARKDOWN" ]; then | ||
| echo "has_content=" >> $GITHUB_OUTPUT | ||
| exit 0 | ||
| fi | ||
| echo "has_content=true" >> $GITHUB_OUTPUT | ||
| # Split markdown into chunks of <= 3000 characters at newline boundaries. | ||
| # Each chunk will become its own section block in the Slack payload. | ||
| CHUNKS='[]' | ||
| BUFFER="" | ||
| while IFS= read -r line; do | ||
| if [ -z "$BUFFER" ]; then | ||
| CANDIDATE="$line" | ||
| else | ||
| CANDIDATE="$BUFFER" | ||
| CANDIDATE+=$'\n' | ||
| CANDIDATE+="$line" | ||
| fi | ||
| if [ ${#CANDIDATE} -gt 3000 ]; then | ||
| # Flush the current buffer as a chunk (if non-empty), start a new one with this line. | ||
| if [ -n "$BUFFER" ]; then | ||
| CHUNKS=$(echo "$CHUNKS" | jq --arg chunk "$BUFFER" '. + [$chunk]') | ||
| fi | ||
| BUFFER="$line" | ||
| else | ||
| BUFFER="$CANDIDATE" | ||
| fi | ||
| done <<< "$MARKDOWN" | ||
| # Flush the remaining buffer. | ||
| if [ -n "$BUFFER" ]; then | ||
| CHUNKS=$(echo "$CHUNKS" | jq --arg chunk "$BUFFER" '. + [$chunk]') | ||
| fi | ||
| # Build the full Slack Block Kit payload: header block + one section block per chunk. | ||
| PAYLOAD=$(echo "$CHUNKS" | jq -c \ | ||
| --arg version "$RELEASE_TAG" \ | ||
| '{blocks: ([{type: "header", text: {type: "plain_text", text: ("Changelog for " + $version)}}] + [.[] | {type: "section", text: {type: "mrkdwn", text: .}}])}') | ||
| echo "payload<<SLACK_PAYLOAD_EOF" >> $GITHUB_OUTPUT | ||
| echo "$PAYLOAD" >> $GITHUB_OUTPUT | ||
| echo "SLACK_PAYLOAD_EOF" >> $GITHUB_OUTPUT | ||
| - name: Post to a Slack channel | ||
| id: slack | ||
| uses: slackapi/slack-github-action@410ae57cff5c6b682b106440be0e6c7eb8c98c9d # v1.16.0 | ||
| if: ${{ steps.build_slack_payload.outputs.has_content == 'true' }} | ||
| # Continue on with the rest of the workflow, even if we fail to send the | ||
| # changelog info to Slack. (We still want to stick the changelog JSON | ||
| # in Cloud Storage.) | ||
| continue-on-error: true | ||
| with: | ||
| channel-id: ${{ steps.get-config.outputs.changelog_slack_channel }} | ||
| payload: ${{ steps.build_slack_payload.outputs.payload }} | ||
| env: | ||
| SLACK_BOT_TOKEN: ${{ secrets.SLACK_CHANGELOG_BOT }} | ||
| - name: Generate changelog.json | ||
| id: changelog_json | ||
| env: | ||
| CHANGELOG: ${{ steps.generate_changelog.outputs.changelog }} | ||
| run: | | ||
| # Compute the current date/time in the necessary format. | ||
| DATE=$(date +%Y-%m-%dT%k:%M:%S%z) | ||
| # Rename the "newFeatures" and "improvements" keys in the Changelog JSON to something more human readable | ||
| # and ignore everything else since this is for the in-app changelog. | ||
| CHANGELOG_SECTIONS=$(echo $CHANGELOG | jq 'with_entries(select(.key == "newFeatures" or .key == "improvements"))' | jq 'with_entries(if .key == "newFeatures" then .key = "New features" else . end)' | jq 'with_entries(if .key == "improvements" then .key = "Improvements" else . end)') | ||
| # create markdown strings for the New Features and Improvements sections | ||
| NEW_FEATURES=$(echo $CHANGELOG_SECTIONS | jq 'with_entries(select(.key == "New features"))' | jq -r 'to_entries[] | "* \(.value[])"' | awk -v ORS='\n' '1') | ||
| IMPROVEMENTS=$(echo $CHANGELOG_SECTIONS | jq 'with_entries(select(.key == "Improvements"))' | jq -r 'to_entries[] | "* \(.value[])"' | awk -v ORS='\n' '1') | ||
| # Extract the image URL from the list, and use the latest URL even if there are multiple | ||
| IMAGE=$(echo $CHANGELOG | jq -r '.images | if length > 0 then .[-1] else "" end') | ||
| # Extract Oz updates as a JSON array | ||
| OZ_UPDATES=$(echo $CHANGELOG | jq -c '.oz_updates // []') | ||
| # Tweak the structure of the JSON, add in a top-level date field, and add in the markdown_sections field | ||
| CHANGELOG=$(echo $CHANGELOG_SECTIONS | jq --arg date "$DATE" --arg new_features "$NEW_FEATURES" --arg improvements "$IMPROVEMENTS" --arg image "$IMAGE" --argjson oz_updates "$OZ_UPDATES" '{"date": $date, "sections": to_entries | map({"title": .key, "items": .value}), "markdown_sections": [{"title": "New features", "markdown": $new_features}, {"title": "Improvements", "markdown": $improvements}, {"title": "Coming soon", "markdown": ""}]} + (if $image != "" then {"image_url": $image} else {} end) + (if ($oz_updates | length) > 0 then {"oz_updates": $oz_updates} else {} end)') | ||
| echo $CHANGELOG > changelog.json | ||
| cat changelog.json | ||
| shell: bash | ||
| - uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 | ||
| with: | ||
| credentials_json: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} | ||
| - name: Upload changelog.json to Google Cloud Storage | ||
| uses: google-github-actions/upload-cloud-storage@e95a15f226403ed658d3e65f40205649f342ba2c # v1 | ||
| with: | ||
| path: changelog.json | ||
| destination: warp-releases/${{ steps.get-config.outputs.channel }}/${{ needs.prepare_release.outputs.release_tag }} | ||