Skip to content

Auto Update Workflow #81

Auto Update Workflow

Auto Update Workflow #81

Workflow file for this run

name: Auto Update Workflow
on:
workflow_dispatch:
inputs:
platform:
description: "Target platform (windows/macos)"
required: true
type: choice
options:
- all platforms
- macos
- windows
- linux
criticalUpdate:
description: "Whether to create a critical update"
required: false
type: boolean
default: false
appflowyVersion:
description: "AppFlowy Release version (leave empty for latest)"
required: false
type: string
releaseVersionNumber:
description: "Release version number (leave empty for latest)"
required: false
type: string
repoOwner:
description: "Repository owner (leave empty for AppFlowy)"
required: false
type: string
default: "AppFlowy-IO"
repoName:
description: "Repository name (leave empty for AppFlowy)"
required: false
type: string
default: "AppFlowy"
env:
FLUTTER_VERSION: "3.27.4"
RUST_TOOLCHAIN: "1.85.0"
jobs:
macos-x86_64:
runs-on: macos-latest
if: ${{ github.event.inputs.platform == 'all platforms' || github.event.inputs.platform == 'macos' }}
steps:
- uses: actions/checkout@v3
with:
repository: ${{ github.event.inputs.repoOwner }}/${{ github.event.inputs.repoName }}
ref: main
- name: Install Flutter
uses: subosito/flutter-action@v2
with:
cache: true
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
- name: Get latest release if version not specified
if: ${{ github.event.inputs.appflowyVersion == '' }}
id: latest_release
uses: actions/github-script@v6
with:
script: |
const release = await github.rest.repos.getLatestRelease({
owner: '${{ github.event.inputs.repoOwner }}',
repo: '${{ github.event.inputs.repoName }}'
});
core.setOutput('version', release.data.tag_name);
- name: Get specific release if version specified
if: ${{ github.event.inputs.appflowyVersion != '' }}
id: specific_release
uses: actions/github-script@v6
with:
script: |
const release = await github.rest.repos.getReleaseByTag({
owner: '${{ github.event.inputs.repoOwner }}',
repo: '${{ github.event.inputs.repoName }}',
tag: '${{ github.event.inputs.appflowyVersion }}'
});
core.setOutput('version', release.data.tag_name);
- name: Download release asset
working-directory: frontend/appflowy_flutter
run: |
VERSION=${{ steps.latest_release.outputs.version || steps.specific_release.outputs.version }}
ASSETS_URL=https://github.com/${{ github.event.inputs.repoOwner }}/${{ github.event.inputs.repoName }}/releases/download/$VERSION/AppFlowy-$VERSION-macos-x86_64.dmg
echo "Downloading $ASSETS_URL"
curl -L -o app.dmg $ASSETS_URL
- name: Generate EdSignature for macOS
working-directory: frontend/appflowy_flutter
run: |
flutter pub get && flutter packages pub get && cd macos && pod install && cd ..
echo ${{ secrets.MACOS_AUTO_UPDATE_PRIVATE_KEY }} > PRIVATE_KEY
dart run auto_updater:sign_update -f PRIVATE_KEY app.dmg > edSignature.txt
echo "EdSignature file content:"
cat edSignature.txt
- name: Generate Appcast.xml
working-directory: frontend/appflowy_flutter
run: |
VERSION=${{ steps.latest_release.outputs.version || steps.specific_release.outputs.version }}
if [ "${{ github.event.inputs.releaseVersionNumber }}" != "" ]; then
RELEASE_VERSION_NUMBER=${{ github.event.inputs.releaseVersionNumber }}
else
RELEASE_VERSION_NUMBER=$VERSION
fi
SIGNATURE=$(grep -o 'sparkle:edSignature="[^"]*"' edSignature.txt | cut -d'"' -f2)
LENGTH=$(grep -o 'length="[^"]*"' edSignature.txt | cut -d'"' -f2 | tr -d '\n')
ASSETS_URL=https://github.com/${{ github.event.inputs.repoOwner }}/${{ github.event.inputs.repoName }}/releases/download/$VERSION/AppFlowy-$VERSION-macos-x86_64.dmg
echo "VERSION: $VERSION"
echo "SIGNATURE: $SIGNATURE"
echo "LENGTH: $LENGTH"
APPCAST_FILE_NAME="appcast-macos-x86_64.xml"
# Create appcast.xml
echo '<?xml version="1.0" encoding="UTF-8"?>' > $APPCAST_FILE_NAME
echo '<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">' >> $APPCAST_FILE_NAME
echo ' <channel>' >> $APPCAST_FILE_NAME
echo ' <title>AppFlowy</title>' >> $APPCAST_FILE_NAME
echo ' <description>Most recent updates to AppFlowy</description>' >> $APPCAST_FILE_NAME
echo ' <language>en</language>' >> $APPCAST_FILE_NAME
echo ' <item>' >> $APPCAST_FILE_NAME
echo " <title>Version $RELEASE_VERSION_NUMBER</title>" >> $APPCAST_FILE_NAME
echo " <sparkle:version>2</sparkle:version>" >> $APPCAST_FILE_NAME
echo " <sparkle:shortVersionString>$RELEASE_VERSION_NUMBER</sparkle:shortVersionString>" >> $APPCAST_FILE_NAME
if [ "${{ github.event.inputs.criticalUpdate }}" = "true" ]; then
echo " <sparkle:criticalUpdate>true</sparkle:criticalUpdate>" >> $APPCAST_FILE_NAME
fi
echo " <pubDate>$(date -R)</pubDate>" >> $APPCAST_FILE_NAME
echo " <enclosure" >> $APPCAST_FILE_NAME
echo " url=\"$ASSETS_URL\"" >> $APPCAST_FILE_NAME
echo " sparkle:os=\"macos\"" >> $APPCAST_FILE_NAME
echo " type=\"application/octet-stream\"" >> $APPCAST_FILE_NAME
echo " sparkle:edSignature=\"$SIGNATURE\"" >> $APPCAST_FILE_NAME
echo " length=\"$LENGTH\"" >> $APPCAST_FILE_NAME
echo " />" >> $APPCAST_FILE_NAME
echo ' </item>' >> $APPCAST_FILE_NAME
echo ' </channel>' >> $APPCAST_FILE_NAME
echo '</rss>' >> $APPCAST_FILE_NAME
echo "Generated $APPCAST_FILE_NAME:"
cat $APPCAST_FILE_NAME
- name: Upload Appcast files
uses: actions/upload-artifact@v4
with:
name: appcast-macos-x86_64.xml
path: |
frontend/appflowy_flutter/appcast-macos-x86_64.xml
if-no-files-found: error
compression-level: 0
macos-arm64:
runs-on: macos-latest
if: ${{ github.event.inputs.platform == 'all platforms' || github.event.inputs.platform == 'macos' }}
steps:
- uses: actions/checkout@v3
with:
repository: ${{ github.event.inputs.repoOwner }}/${{ github.event.inputs.repoName }}
ref: main
- name: Install Flutter
uses: subosito/flutter-action@v2
with:
cache: true
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
- name: Get latest release if version not specified
if: ${{ github.event.inputs.appflowyVersion == '' }}
id: latest_release
uses: actions/github-script@v6
with:
script: |
const release = await github.rest.repos.getLatestRelease({
owner: '${{ github.event.inputs.repoOwner }}',
repo: '${{ github.event.inputs.repoName }}'
});
core.setOutput('version', release.data.tag_name);
- name: Get specific release if version specified
if: ${{ github.event.inputs.appflowyVersion != '' }}
id: specific_release
uses: actions/github-script@v6
with:
script: |
const release = await github.rest.repos.getReleaseByTag({
owner: '${{ github.event.inputs.repoOwner }}',
repo: '${{ github.event.inputs.repoName }}',
tag: '${{ github.event.inputs.appflowyVersion }}'
});
core.setOutput('version', release.data.tag_name);
- name: Download release asset
working-directory: frontend/appflowy_flutter
run: |
VERSION=${{ steps.latest_release.outputs.version || steps.specific_release.outputs.version }}
ASSETS_URL=https://github.com/${{ github.event.inputs.repoOwner }}/${{ github.event.inputs.repoName }}/releases/download/$VERSION/AppFlowy-$VERSION-macos-universal.dmg
echo "Downloading $ASSETS_URL"
curl -L -o app.dmg $ASSETS_URL
- name: Generate EdSignature for macOS
working-directory: frontend/appflowy_flutter
run: |
flutter pub get && flutter packages pub get && cd macos && pod install && cd ..
echo ${{ secrets.MACOS_AUTO_UPDATE_PRIVATE_KEY }} > PRIVATE_KEY
dart run auto_updater:sign_update -f PRIVATE_KEY app.dmg > edSignature.txt
echo "EdSignature file content:"
cat edSignature.txt
- name: Generate Appcast.xml
working-directory: frontend/appflowy_flutter
run: |
VERSION=${{ steps.latest_release.outputs.version || steps.specific_release.outputs.version }}
if [ "${{ github.event.inputs.releaseVersionNumber }}" != "" ]; then
RELEASE_VERSION_NUMBER=${{ github.event.inputs.releaseVersionNumber }}
else
RELEASE_VERSION_NUMBER=$VERSION
fi
SIGNATURE=$(grep -o 'sparkle:edSignature="[^"]*"' edSignature.txt | cut -d'"' -f2)
LENGTH=$(grep -o 'length="[^"]*"' edSignature.txt | cut -d'"' -f2 | tr -d '\n')
ASSETS_URL=https://github.com/${{ github.event.inputs.repoOwner }}/${{ github.event.inputs.repoName }}/releases/download/$VERSION/AppFlowy-$VERSION-macos-universal.dmg
echo "VERSION: $VERSION"
echo "SIGNATURE: $SIGNATURE"
echo "LENGTH: $LENGTH"
APPCAST_FILE_NAME="appcast-macos-arm64.xml"
# Create appcast.xml
echo '<?xml version="1.0" encoding="UTF-8"?>' > $APPCAST_FILE_NAME
echo '<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">' >> $APPCAST_FILE_NAME
echo ' <channel>' >> $APPCAST_FILE_NAME
echo ' <title>AppFlowy</title>' >> $APPCAST_FILE_NAME
echo ' <description>Most recent updates to AppFlowy</description>' >> $APPCAST_FILE_NAME
echo ' <language>en</language>' >> $APPCAST_FILE_NAME
echo ' <item>' >> $APPCAST_FILE_NAME
echo " <title>Version $RELEASE_VERSION_NUMBER</title>" >> $APPCAST_FILE_NAME
echo " <sparkle:version>2</sparkle:version>" >> $APPCAST_FILE_NAME
echo " <sparkle:shortVersionString>$RELEASE_VERSION_NUMBER</sparkle:shortVersionString>" >> $APPCAST_FILE_NAME
if [ "${{ github.event.inputs.criticalUpdate }}" = "true" ]; then
echo " <sparkle:criticalUpdate>true</sparkle:criticalUpdate>" >> $APPCAST_FILE_NAME
fi
echo " <pubDate>$(date -R)</pubDate>" >> $APPCAST_FILE_NAME
echo " <enclosure" >> $APPCAST_FILE_NAME
echo " url=\"$ASSETS_URL\"" >> $APPCAST_FILE_NAME
echo " sparkle:os=\"macos\"" >> $APPCAST_FILE_NAME
echo " type=\"application/octet-stream\"" >> $APPCAST_FILE_NAME
echo " sparkle:edSignature=\"$SIGNATURE\"" >> $APPCAST_FILE_NAME
echo " length=\"$LENGTH\"" >> $APPCAST_FILE_NAME
echo " />" >> $APPCAST_FILE_NAME
echo ' </item>' >> $APPCAST_FILE_NAME
echo ' </channel>' >> $APPCAST_FILE_NAME
echo '</rss>' >> $APPCAST_FILE_NAME
echo "Generated $APPCAST_FILE_NAME:"
cat $APPCAST_FILE_NAME
- name: Upload Appcast files
uses: actions/upload-artifact@v4
with:
name: appcast-macos-arm64.xml
path: |
frontend/appflowy_flutter/appcast-macos-arm64.xml
if-no-files-found: error
compression-level: 0
windows-x86_64:
runs-on: windows-latest
if: ${{ github.event.inputs.platform == 'all platforms' || github.event.inputs.platform == 'windows' }}
steps:
- uses: actions/checkout@v3
with:
repository: ${{ github.event.inputs.repoOwner }}/${{ github.event.inputs.repoName }}
ref: main
- name: Install Flutter
uses: subosito/flutter-action@v2
with:
cache: true
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
target: x86_64-pc-windows-msvc
override: true
components: rustfmt
profile: minimal
- uses: davidB/rust-cargo-make@v1
with:
version: "0.37.5"
- name: Install prerequisites
working-directory: frontend
run: |
vcpkg integrate install
cargo install duckscript_cli --force --locked
- name: Get latest release if version not specified
if: ${{ github.event.inputs.appflowyVersion == '' }}
id: latest_release
uses: actions/github-script@v6
with:
script: |
const release = await github.rest.repos.getLatestRelease({
owner: '${{ github.event.inputs.repoOwner }}',
repo: '${{ github.event.inputs.repoName }}'
});
core.setOutput('version', release.data.tag_name);
- name: Get specific release if version specified
if: ${{ github.event.inputs.appflowyVersion != '' }}
id: specific_release
uses: actions/github-script@v6
with:
script: |
const release = await github.rest.repos.getReleaseByTag({
owner: '${{ github.event.inputs.repoOwner }}',
repo: '${{ github.event.inputs.repoName }}',
tag: '${{ github.event.inputs.appflowyVersion }}'
});
core.setOutput('version', release.data.tag_name);
- name: Download release asset
working-directory: frontend/appflowy_flutter
run: |
$VERSION="${{ steps.latest_release.outputs.version || steps.specific_release.outputs.version }}"
$ASSETS_URL="https://github.com/${{ github.event.inputs.repoOwner }}/${{ github.event.inputs.repoName }}/releases/download/$VERSION/AppFlowy-$VERSION-windows-x86_64.exe"
echo "Downloading $ASSETS_URL"
curl -L -o app.exe $ASSETS_URL
- name: Install OpenSSL
shell: powershell
run: |
vcpkg install openssl:x64-windows
- name: Build AppFlowy
working-directory: frontend
run: |
flutter config --enable-windows-desktop
flutter pub get && flutter packages pub get
dart ./scripts/flutter_release_build/build_flowy.dart exclude-directives . $VERSION
cargo make --profile development-windows-x86 appflowy
- name: Generate EdSignature for Windows
working-directory: frontend/appflowy_flutter
shell: bash
run: |
if [ -f dsa_priv.pem ] && [ -s dsa_priv.pem ]; then
echo "Using repository dsa_priv.pem"
elif [ -n "${{ secrets.WINDOWS_AUTO_UPDATE_PRIVATE_KEY }}" ]; then
printf "%s" "${{ secrets.WINDOWS_AUTO_UPDATE_PRIVATE_KEY }}" > dsa_priv.pem
else
echo "Missing DSA private key (dsa_priv.pem or WINDOWS_AUTO_UPDATE_PRIVATE_KEY)." >&2
exit 1
fi
dart run auto_updater:sign_update app.exe > edSignature.txt
echo "EdSignature file content:"
cat edSignature.txt
- name: Generate Appcast.xml
working-directory: frontend/appflowy_flutter
run: |
$VERSION="${{ steps.latest_release.outputs.version || steps.specific_release.outputs.version }}"
if ("${{ github.event.inputs.releaseVersionNumber }}" -ne "") {
$RELEASE_VERSION_NUMBER="${{ github.event.inputs.releaseVersionNumber }}"
} else {
$RELEASE_VERSION_NUMBER=$VERSION
}
$ASSETS_URL="https://github.com/${{ github.event.inputs.repoOwner }}/${{ github.event.inputs.repoName }}/releases/download/$VERSION/AppFlowy-$VERSION-windows-x86_64.exe"
$edSignatureContent = Get-Content edSignature.txt -Raw
$SIGNATURE = if ($edSignatureContent -match 'sparkle:dsaSignature="([^"]*)"') { $matches[1] } else { "" }
$LENGTH = if ($edSignatureContent -match 'length="([^"]*)"') { $matches[1] } else { "0" }
Write-Host "VERSION: $VERSION"
Write-Host "SIGNATURE: $SIGNATURE"
Write-Host "LENGTH: $LENGTH"
$APPCAST_FILE_NAME="appcast-windows-x86_64.xml"
$PUBDATE = Get-Date -Format "r"
$criticalUpdateLine = ""
if ("${{ github.event.inputs.criticalUpdate }}" -eq "true") {
$criticalUpdateLine = " <sparkle:criticalUpdate>true</sparkle:criticalUpdate>"
}
# Create appcast.xml
@"
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
<channel>
<title>AppFlowy</title>
<description>Most recent updates to AppFlowy</description>
<language>en</language>
<item>
<title>Version $RELEASE_VERSION_NUMBER</title>
<sparkle:version>$RELEASE_VERSION_NUMBER</sparkle:version>
<sparkle:shortVersionString>$RELEASE_VERSION_NUMBER</sparkle:shortVersionString>
$criticalUpdateLine
<pubDate>$PUBDATE</pubDate>
<enclosure
url="$ASSETS_URL"
sparkle:os="windows"
type="application/octet-stream"
sparkle:dsaSignature="$SIGNATURE"
length="$LENGTH"
/>
</item>
</channel>
</rss>
"@ | Set-Content -Path $APPCAST_FILE_NAME
Write-Host "Generated ${APPCAST_FILE_NAME}:"
Get-Content $APPCAST_FILE_NAME
- name: Upload Appcast files
uses: actions/upload-artifact@v4
with:
name: appcast-windows-x86_64.xml
path: |
frontend/appflowy_flutter/appcast-windows-x86_64.xml
if-no-files-found: error
compression-level: 0
linux-x86_64:
runs-on: ubuntu-latest
if: ${{ github.event.inputs.platform == 'all platforms' || github.event.inputs.platform == 'linux' }}
steps:
- uses: actions/checkout@v3
with:
repository: ${{ github.event.inputs.repoOwner }}/${{ github.event.inputs.repoName }}
ref: main
- name: Get latest release if version not specified
if: ${{ github.event.inputs.appflowyVersion == '' }}
id: latest_release
uses: actions/github-script@v6
with:
script: |
const release = await github.rest.repos.getLatestRelease({
owner: '${{ github.event.inputs.repoOwner }}',
repo: '${{ github.event.inputs.repoName }}'
});
core.setOutput('version', release.data.tag_name);
- name: Get specific release if version specified
if: ${{ github.event.inputs.appflowyVersion != '' }}
id: specific_release
uses: actions/github-script@v6
with:
script: |
const release = await github.rest.repos.getReleaseByTag({
owner: '${{ github.event.inputs.repoOwner }}',
repo: '${{ github.event.inputs.repoName }}',
tag: '${{ github.event.inputs.appflowyVersion }}'
});
core.setOutput('version', release.data.tag_name);
- name: Generate Appcast.xml
working-directory: frontend/appflowy_flutter
run: |
VERSION=${{ steps.latest_release.outputs.version || steps.specific_release.outputs.version }}
if [ "${{ github.event.inputs.releaseVersionNumber }}" != "" ]; then
RELEASE_VERSION_NUMBER=${{ github.event.inputs.releaseVersionNumber }}
else
RELEASE_VERSION_NUMBER=$VERSION
fi
echo "VERSION: $VERSION"
APPCAST_FILE_NAME="appcast-linux-x86_64.xml"
# Create appcast.xml
echo '<?xml version="1.0" encoding="UTF-8"?>' > $APPCAST_FILE_NAME
echo '<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">' >> $APPCAST_FILE_NAME
echo ' <channel>' >> $APPCAST_FILE_NAME
echo ' <title>AppFlowy</title>' >> $APPCAST_FILE_NAME
echo ' <description>Most recent updates to AppFlowy</description>' >> $APPCAST_FILE_NAME
echo ' <language>en</language>' >> $APPCAST_FILE_NAME
echo ' <item>' >> $APPCAST_FILE_NAME
echo " <title>Version $RELEASE_VERSION_NUMBER</title>" >> $APPCAST_FILE_NAME
echo " <sparkle:version>2</sparkle:version>" >> $APPCAST_FILE_NAME
echo " <sparkle:shortVersionString>$RELEASE_VERSION_NUMBER</sparkle:shortVersionString>" >> $APPCAST_FILE_NAME
if [ "${{ github.event.inputs.criticalUpdate }}" = "true" ]; then
echo " <sparkle:criticalUpdate>true</sparkle:criticalUpdate>" >> $APPCAST_FILE_NAME
fi
echo " <pubDate>$(date -R)</pubDate>" >> $APPCAST_FILE_NAME
echo " <enclosure" >> $APPCAST_FILE_NAME
echo " sparkle:os=\"linux\"" >> $APPCAST_FILE_NAME
echo " type=\"application/octet-stream\"" >> $APPCAST_FILE_NAME
echo " />" >> $APPCAST_FILE_NAME
echo ' </item>' >> $APPCAST_FILE_NAME
echo ' </channel>' >> $APPCAST_FILE_NAME
echo '</rss>' >> $APPCAST_FILE_NAME
echo "Generated $APPCAST_FILE_NAME:"
cat $APPCAST_FILE_NAME
- name: Upload Appcast files
uses: actions/upload-artifact@v4
with:
name: appcast-linux-x86_64.xml
path: |
frontend/appflowy_flutter/appcast-linux-x86_64.xml
if-no-files-found: error
compression-level: 0