Skip to content

build apk

build apk #576

Workflow file for this run

# Build APKs for Kiwi Browser
name: build apk
# Controls when the action will run. Triggers the workflow on push or pull request events
on:
workflow_dispatch:
inputs:
prepareRelease:
description: 'Create a draft release in Google Play Store'
required: true
default: 'no'
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
build:
# The type of runner that the job will run on
runs-on: ubuntu-20.04
strategy:
fail-fast: false
max-parallel: 4
matrix:
platform: [arm, arm64, x86, x64]
# The GitHub Actions machines have a "slow disk", and a SSD "fast" disk.
# However, there is not enough space to do all the processing on the SSD.
# We refer to the disks based on their name in /dev/disk
# /dev/disk/azure/root-part1 is / ("slow disk")
# /dev/disk/azure/resource-part1 is a 14 GB ephemeral SSD disk mounted in /mnt
# We store the source-code repository (kiwibrowser/src) on /dev/disk/azure/root-part1
# We store cache, dependencies and output on /dev/disk/azure/resource-part1 (SSD)
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- name: Initializing build
run: echo Initializing build for platform ${{ matrix.platform }}
- name: Reclaiming disk space on / by disabling swap partition
run: |
sudo swapoff -av
sudo rm -f /swapfile
- name: Reclaiming disk space on / by removing .NET framework
run: sudo rm -rf /usr/share/dotnet
- name: Checking-out source-code in $GITHUB_WORKSPACE
uses: actions/checkout@v2
- name: Creating secondary disk folder on /dev/disk/azure/resource-part1 (SSD)
run: |
sudo mkdir -p /extended_data
sudo chown -R runner:docker /extended_data
# If you want to use only the SSD, you can use:
- name: On SSD - Creating symlink on /dev/disk/azure/root-part1 pointing to /dev/disk/azure/resource-part1
run: |
sudo ln -s /extended_data /mnt/secondary_disk
sudo ln -s /mnt/secondary_disk $GITHUB_WORKSPACE/
# or alternatively, to work on the main partition
# - name: On HDD - Creating symlink on /dev/disk/azure/root-part1 pointing to /dev/disk/azure/resource-part1
# run: |
# sudo ln -s /extended_data /mnt/secondary_disk
# sudo ln -s /mnt/secondary_disk $GITHUB_WORKSPACE/
# We cannot checkout outside of $GITHUB_WORKSPACE, but we want to checkout to the SSD
# so we have a symbolic link $GITHUB_WORKSPACE/secondary_disk/ pointing to the SSD
# and checkout the code there
- name: Checking-out CIPD dependencies in /mnt/secondary_disk/.cipd
uses: actions/checkout@v2
with:
repository: kiwibrowser/dependencies
path: ./secondary_disk/.cipd
- name: Linking .cipd in the proper path and copying .gclient and .gclient_entries
run: |
ln -s $GITHUB_WORKSPACE/./secondary_disk/.cipd ..
cp ../.cipd/.gclient ..
cp ../.cipd/.gclient_entries ..
- name: Installing rclone
run: curl https://rclone.org/install.sh | sudo bash
- name: Updating APT repository
run: sudo apt-get update
- name: Installing Python and OpenJDK
run: sudo apt-get install -y python openjdk-8-jdk-headless libncurses5 ccache ninja-build
- name: Installing system dependencies
run: |
sudo bash install-build-deps.sh --no-chromeos-fonts
build/linux/sysroot_scripts/install-sysroot.py --arch=i386
build/linux/sysroot_scripts/install-sysroot.py --arch=amd64
- name: Creating output folder
run: mkdir -p secondary_disk/out/android_${{ matrix.platform }}
- name: Generating one-time APK signature key
run: keytool -genkey -v -keystore keystore.jks -alias dev -keyalg RSA -keysize 2048 -validity 10000 -storepass public_password -keypass public_password -dname "cn=Kiwi Browser (unverified), ou=Actions, o=Kiwi Browser, c=GitHub"
- name: Copying args.gn to target folder
run: cat .build/android_arm/args.gn | sed "s#target_cpu = \"arm\"#target_cpu = \"${{ matrix.platform }}\"#" | sed "s#android_default_version_name = \"Git\"#android_default_version_name = \"Git$(date '+%y%m%d')Gen${{ github.run_id }}\"#" > secondary_disk/out/android_${{ matrix.platform }}/args.gn
- name: Modifying args.gn (arm)
if: matrix.platform == 'arm'
run: sed -i "s#android_default_version_code = \"1\"#android_default_version_code = \"$(date '+%y%m%d')1\"#" secondary_disk/out/android_${{ matrix.platform }}/args.gn
- name: Modifying args.gn (arm64)
if: matrix.platform == 'arm64'
run: sed -i "s#android_default_version_code = \"1\"#android_default_version_code = \"$(date '+%y%m%d')2\"#" secondary_disk/out/android_${{ matrix.platform }}/args.gn
- name: Modifying args.gn (x86)
if: matrix.platform == 'x86'
run: sed -i "s#android_default_version_code = \"1\"#android_default_version_code = \"$(date '+%y%m%d')3\"#" secondary_disk/out/android_${{ matrix.platform }}/args.gn
- name: Modifying args.gn (x64)
if: matrix.platform == 'x64'
run: sed -i "s#android_default_version_code = \"1\"#android_default_version_code = \"$(date '+%y%m%d')4\"#" secondary_disk/out/android_${{ matrix.platform }}/args.gn
- name: Displaying args.gn
run: cat secondary_disk/out/android_${{ matrix.platform }}/args.gn
- name: Downloading depot_tools
working-directory: ./secondary_disk
run: git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
- name: Adding depot_tools to path
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: echo "::add-path::$GITHUB_WORKSPACE/secondary_disk/depot_tools"
- name: Setting environment variables
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: |
echo "::set-env name=CC::ccache clang -Qunused-arguments"
echo "::set-env name=CXX::ccache clang++ -Qunused-arguments"
- name: Checking available disk-space
run: df -h
- name: Creating rclone config
run: |
mkdir -p $HOME/.config/rclone/
echo '[cache]' > $HOME/.config/rclone/rclone.conf
echo 'type = sftp' >> $HOME/.config/rclone/rclone.conf
echo 'host = ${{ secrets.STORAGE_HOST }}' >> $HOME/.config/rclone/rclone.conf
echo 'user = storage' >> $HOME/.config/rclone/rclone.conf
echo 'key_pem = ${{ secrets.STORAGE_KEY }}' >> $HOME/.config/rclone/rclone.conf
- name: Creating cache folder on /dev/disk/azure/resource-part1 (SSD)
run: |
sudo mkdir -p /mnt/cache
sudo chown -R runner:docker /mnt/cache
- name: Creating symlink in $HOME/cache pointing to cache on /dev/disk/azure/resource-part1
run: ln -s /mnt/cache $HOME/
- name: Downloading binary objects cache to $HOME/cache
run: rclone copy --fast-list --transfers=128 cache:kiwibrowser-ccache-${{ matrix.platform }} $HOME/cache
- name: Checking available disk-space after downloading cache
run: df -h
- name: Fetching number for the latest stable version of Chromium
run: curl "https://omahaproxy.appspot.com/all" | grep -Fi "android,stable" | cut -f3 -d"," | awk '{split($0,a,"."); print "MAJOR=" a[1] "\nMINOR=" a[2] "\nBUILD=" a[3] "\nPATCH=" a[4]}' > chrome/VERSION
- name: Calculating cache size
run: du -csh $HOME/cache
- name: Creating ccache configuration
run: |
mkdir -p $HOME/.ccache/
echo 'compiler_check = none' >> $HOME/.ccache/ccache.conf
echo "stats = false" >> $HOME/.ccache/ccache.conf
echo 'max_size = 20G' >> $HOME/.ccache/ccache.conf
echo "base_dir = $HOME" >> $HOME/.ccache/ccache.conf
echo "cache_dir = $HOME/cache" >> $HOME/.ccache/ccache.conf
echo "hash_dir = false" >> $HOME/.ccache/ccache.conf
- name: Running gclient runhooks
run: gclient runhooks
- name: Generating build files
run: gn gen ./secondary_disk/out/android_${{ matrix.platform }}
- name: Checking available disk-space before build cache
run: df -h
- name: Creating rclone config to upload the cache
if: ${{ github.repository_owner == 'kiwibrowser' }}
run: |
echo '[sync]' > $HOME/.config/rclone/rclone.conf
echo 'type = sftp' >> $HOME/.config/rclone/rclone.conf
echo 'host = ${{ secrets.STORAGE_HOST }}' >> $HOME/.config/rclone/rclone.conf
echo 'user = storage' >> $HOME/.config/rclone/rclone.conf
echo 'key_pem = ${{ secrets.STORAGE_KEY }}' >> $HOME/.config/rclone/rclone.conf
- name: Checking available disk-space before build
run: df -h
# We compile component by component as 6 hours is not enough for the initial build
# so we can snapshot between each component and continue further from the snapshot
- name: Compiling source-code (base)
run: ninja -C ./secondary_disk/out/android_${{ matrix.platform }} base
- name: Uploading binary objects to cache
if: ${{ github.repository_owner == 'kiwibrowser' }}
run: rclone copy --fast-list --transfers=32 $HOME/cache/ sync:kiwibrowser-ccache-${{ matrix.platform }}/
- name: Uploading binary objects to cache
if: ${{ github.repository_owner == 'kiwibrowser' }}
run: rclone copy --fast-list --transfers=32 $HOME/cache/ sync:kiwibrowser-ccache-${{ matrix.platform }}/
- name: Compiling source-code (components/guest_view/renderer)
run: ninja -C ./secondary_disk/out/android_${{ matrix.platform }} components/guest_view/renderer
- name: Uploading binary objects to cache
if: ${{ github.repository_owner == 'kiwibrowser' }}
run: rclone copy --fast-list --transfers=32 $HOME/cache/ sync:kiwibrowser-ccache-${{ matrix.platform }}/
- name: Compiling source-code (chrome/gpu)
run: ninja -C ./secondary_disk/out/android_${{ matrix.platform }} chrome/gpu
- name: Uploading binary objects to cache
if: ${{ github.repository_owner == 'kiwibrowser' }}
run: rclone copy --fast-list --transfers=32 $HOME/cache/ sync:kiwibrowser-ccache-${{ matrix.platform }}/
- name: Compiling source-code (chrome_java)
run: ninja -C ./secondary_disk/out/android_${{ matrix.platform }} chrome_java
- name: Uploading binary objects to cache
if: ${{ github.repository_owner == 'kiwibrowser' }}
run: rclone copy --fast-list --transfers=32 $HOME/cache/ sync:kiwibrowser-ccache-${{ matrix.platform }}/
- name: Compiling source-code (components/version_info)
run: ninja -C ./secondary_disk/out/android_${{ matrix.platform }} components/version_info
- name: Compiling source-code (ui/base)
run: ninja -C ./secondary_disk/out/android_${{ matrix.platform }} ui/base
- name: Compiling source-code (chrome/browser:resources)
run: ninja -C ./secondary_disk/out/android_${{ matrix.platform }} chrome/browser:resources
- name: Compiling source-code (chrome/browser/ui)
run: ninja -C ./secondary_disk/out/android_${{ matrix.platform }} chrome/browser/ui
- name: Compiling source-code (chrome/browser)
run: ninja -C ./secondary_disk/out/android_${{ matrix.platform }} chrome/browser
- name: Uploading binary objects to cache
if: ${{ github.repository_owner == 'kiwibrowser' }}
run: rclone copy --fast-list --transfers=32 $HOME/cache/ sync:kiwibrowser-ccache-${{ matrix.platform }}/
- name: Compiling source-code (chrome/common)
run: ninja -C ./secondary_disk/out/android_${{ matrix.platform }} chrome/common
- name: Compiling source-code (chrome/renderer)
run: ninja -C ./secondary_disk/out/android_${{ matrix.platform }} chrome/renderer
- name: Compiling source-code (extensions)
run: ninja -C ./secondary_disk/out/android_${{ matrix.platform }} extensions
- name: Compiling source-code (services)
run: ninja -C ./secondary_disk/out/android_${{ matrix.platform }} services
- name: Compiling source-code (v8)
run: ninja -C ./secondary_disk/out/android_${{ matrix.platform }} v8
- name: Checking available disk-space
run: df -h
- name: Reclaiming disk space
run: sudo rm -rf /mnt/cache/*
- name: Checking available disk-space
run: df -h
- name: Checking available memory
run: free -m
- name: Listing running processes
run: ps auxww
- name: Compiling source-code (final stage)
run: ninja -C ./secondary_disk/out/android_${{ matrix.platform }} chrome_public_apk
- name: Uploading binary objects to cache
if: ${{ github.repository_owner == 'kiwibrowser' }}
run: rclone copy --fast-list --transfers=32 $HOME/cache/ sync:kiwibrowser-ccache-${{ matrix.platform }}/
- name: Generating native symbols mapping
run: |
mkdir -p ./secondary_disk/out/lnx64
echo Copying files...
cp -v ../.cipd/tools/* ./secondary_disk/out/lnx64/
echo Listing files...
ls -la ../.cipd/tools/*
echo Listing files in target...
ls -la ./secondary_disk/out/lnx64
echo Making dump_syms executable...
chmod +x ./secondary_disk/out/lnx64/dump_syms
echo Generating breakpad symbols...
python components/crash/content/tools/generate_breakpad_symbols.py --build-dir=./secondary_disk/out/lnx64 --symbols-dir=/tmp/extracted_symbols/ --binary=./secondary_disk/out/android_${{ matrix.platform }}/lib.unstripped/libchrome.so --clear --verbose
echo Symbols have been generated.
echo Compressing symbols...
tar -czvf ./secondary_disk/out/android_${{ matrix.platform }}/apks/ChromePublic.native.mapping.tar.gz /tmp/extracted_symbols
echo Compression completed.
- name: Uploading APK
uses: actions/upload-artifact@v1
with:
name: apk-${{ matrix.platform }}
path: ./secondary_disk/out/android_${{ matrix.platform }}/apks/
- name: Listing mapping files
run: find ./secondary_disk/out/ -name '*.mapping'
sign_and_upload:
runs-on: ubuntu-latest
needs: build
steps:
- name: Installing rclone
if: ${{ github.repository_owner == 'kiwibrowser' }}
run: curl https://rclone.org/install.sh | sudo bash -s beta
- name: Creating rclone config to upload the APK files
if: ${{ github.repository_owner == 'kiwibrowser' }}
run: |
mkdir -p $HOME/.config/rclone/
echo '[sync]' > $HOME/.config/rclone/rclone.conf
echo 'type = sftp' >> $HOME/.config/rclone/rclone.conf
echo 'host = ${{ secrets.STORAGE_HOST }}' >> $HOME/.config/rclone/rclone.conf
echo 'user = storage' >> $HOME/.config/rclone/rclone.conf
echo 'key_pem = ${{ secrets.STORAGE_KEY }}' >> $HOME/.config/rclone/rclone.conf
- name: Creating release
id: create_release
uses: actions/create-release@v1.1.4
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
owner: "kiwibrowser"
repo: "src"
tag_name: ${{ github.run_id }}
release_name: Generation ${{ github.run_id }}
draft: false
prerelease: true
body: |
Important: This is Kiwi Browser Classic.
Kiwi Browser Classic installs as a separate application (com.kiwibrowser.browser.classic).
The new updates of Kiwi Browser have moved to a new repository.
If you want the latest release of Kiwi Browser, you should go to:
https://github.com/kiwibrowser/src.next/releases
- name: Downloading artifact (arm)
uses: actions/download-artifact@v1
with:
name: apk-arm
- name: Downloading artifact (arm64)
uses: actions/download-artifact@v1
with:
name: apk-arm64
- name: Downloading artifact (x86)
uses: actions/download-artifact@v1
with:
name: apk-x86
- name: Downloading artifact (x64)
uses: actions/download-artifact@v1
with:
name: apk-x64
- name: Uploading mapping file into GitHub release (arm)
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./apk-arm/ChromePublic.apk.mapping
asset_name: com.kiwibrowser.browser.classic-${{ github.run_id }}-arm.mapping
asset_content_type: application/vnd.android.package-archive
- name: Uploading mapping file into GitHub release (arm64)
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./apk-arm64/ChromePublic.apk.mapping
asset_name: com.kiwibrowser.browser.classic-${{ github.run_id }}-arm64.mapping
asset_content_type: application/vnd.android.package-archive
- name: Uploading mapping file into GitHub release (x86)
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./apk-x86/ChromePublic.apk.mapping
asset_name: com.kiwibrowser.browser.classic-${{ github.run_id }}-x86.mapping
asset_content_type: application/vnd.android.package-archive
- name: Uploading mapping file into GitHub release (x64)
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./apk-x64/ChromePublic.apk.mapping
asset_name: com.kiwibrowser.browser.classic-${{ github.run_id }}-x64.mapping
asset_content_type: application/vnd.android.package-archive
- name: Uploading native mapping file into GitHub release (arm)
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./apk-arm/ChromePublic.native.mapping.tar.gz
asset_name: com.kiwibrowser.browser.classic-${{ github.run_id }}-arm.native.mapping.tar.gz
asset_content_type: application/vnd.android.package-archive
- name: Uploading native mapping file into GitHub release (arm64)
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./apk-arm64/ChromePublic.native.mapping.tar.gz
asset_name: com.kiwibrowser.browser.classic-${{ github.run_id }}-arm64.native.mapping.tar.gz
asset_content_type: application/vnd.android.package-archive
- name: Uploading native mapping file into GitHub release (x86)
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./apk-x86/ChromePublic.native.mapping.tar.gz
asset_name: com.kiwibrowser.browser.classic-${{ github.run_id }}-x86.native.mapping.tar.gz
asset_content_type: application/vnd.android.package-archive
- name: Uploading native mapping file into GitHub release (x64)
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./apk-x64/ChromePublic.native.mapping.tar.gz
asset_name: com.kiwibrowser.browser.classic-${{ github.run_id }}.x64.native.mapping.tar.gz
asset_content_type: application/vnd.android.package-archive
- name: Uploading artifacts to storage
if: ${{ github.repository_owner == 'kiwibrowser' }}
run: |
rclone copy --fast-list --transfers=16 ./apk-arm/ChromePublic.apk sync:kiwibrowser-builds/${{ github.run_id }}/arm/
rclone copy --fast-list --transfers=16 ./apk-arm64/ChromePublic.apk sync:kiwibrowser-builds/${{ github.run_id }}/arm64/
rclone copy --fast-list --transfers=16 ./apk-x86/ChromePublic.apk sync:kiwibrowser-builds/${{ github.run_id }}/x86/
rclone copy --fast-list --transfers=16 ./apk-x64/ChromePublic.apk sync:kiwibrowser-builds/${{ github.run_id }}/x64/
rclone copy --fast-list --transfers=16 ./apk-arm/ChromePublic.apk.mapping sync:kiwibrowser-builds/${{ github.run_id }}/arm/
rclone copy --fast-list --transfers=16 ./apk-arm64/ChromePublic.apk.mapping sync:kiwibrowser-builds/${{ github.run_id }}/arm64/
rclone copy --fast-list --transfers=16 ./apk-x86/ChromePublic.apk.mapping sync:kiwibrowser-builds/${{ github.run_id }}/x86/
rclone copy --fast-list --transfers=16 ./apk-x64/ChromePublic.apk.mapping sync:kiwibrowser-builds/${{ github.run_id }}/x64/
- name: Signing and uploading release to GitHub
if: ${{ github.repository_owner == 'kiwibrowser' && !contains(github.event.head_commit.message, 'release') }}
run: |
curl 'https://${{ secrets.RELEASE_HOST }}/?run_id=${{ github.run_id }}&dk=${{ secrets.DEPLOY_KEY }}'
- name: Signing and uploading release to GitHub and send to the Play Store
if: ${{ github.repository_owner == 'kiwibrowser' && contains(github.event.inputs.prepareRelease, 'yes') }}
run: |
curl 'https://${{ secrets.RELEASE_HOST }}/?run_id=${{ github.run_id }}&dk=${{ secrets.DEPLOY_KEY }}&publish=1&target=apk'
- name: Downloading artifacts from storage
if: ${{ github.repository_owner == 'kiwibrowser' }}
run: |
rclone copy --fast-list --transfers=128 sync:kiwibrowser-builds/${{ github.run_id }}/arm/ ./apk-arm
rclone copy --fast-list --transfers=128 sync:kiwibrowser-builds/${{ github.run_id }}/arm64/ ./apk-arm64
rclone copy --fast-list --transfers=128 sync:kiwibrowser-builds/${{ github.run_id }}/x86/ ./apk-x86
rclone copy --fast-list --transfers=128 sync:kiwibrowser-builds/${{ github.run_id }}/x64/ ./apk-x64
- name: Uploading release asset (arm-signed)
if: ${{ github.repository_owner == 'kiwibrowser' }}
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./apk-arm/ChromePublic-DevSigned.apk
asset_name: com.kiwibrowser.browser.classic-${{ github.run_id }}-arm-signed.apk
asset_content_type: application/vnd.android.package-archive
- name: Uploading release asset (arm64-signed)
if: ${{ github.repository_owner == 'kiwibrowser' }}
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./apk-arm64/ChromePublic-DevSigned.apk
asset_name: com.kiwibrowser.browser.classic-${{ github.run_id }}-arm64-signed.apk
asset_content_type: application/vnd.android.package-archive
- name: Uploading release asset (x86-signed)
if: ${{ github.repository_owner == 'kiwibrowser' }}
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./apk-x86/ChromePublic-DevSigned.apk
asset_name: com.kiwibrowser.browser.classic-${{ github.run_id }}-x86-signed.apk
asset_content_type: application/vnd.android.package-archive
- name: Uploading release asset (x64-signed)
if: ${{ github.repository_owner == 'kiwibrowser' }}
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./apk-x64/ChromePublic-DevSigned.apk
asset_name: com.kiwibrowser.browser.classic-${{ github.run_id }}-x64-signed.apk
asset_content_type: application/vnd.android.package-archive
- name: Send announcement on Discord
if: ${{ github.repository_owner == 'kiwibrowser' }}
run: |
curl -H 'Content-Type: application/json' -X POST -d '{"username": "Kiwi Builder", "content": "A new build of Kiwi Browser (classic) is available: https://github.com/kiwibrowser/src/releases/tag/${{ github.run_id }}"}' ${{ secrets.DISCORD_WEBHOOK }}