Skip to content

Commit 84bc9bc

Browse files
authored
chore(docs): add macOS desktop release instructions for sparkle (#962)
1 parent a62b76d commit 84bc9bc

File tree

6 files changed

+202
-41
lines changed

6 files changed

+202
-41
lines changed

.github/workflows/desktop_macos_make.yml

Lines changed: 0 additions & 33 deletions
This file was deleted.

.github/workflows/desktop_make.yml

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
name: Desktop package apps
2+
on:
3+
workflow_dispatch:
4+
push:
5+
6+
concurrency:
7+
group: desktop-packaging-${{ github.ref }}
8+
cancel-in-progress: false
9+
10+
jobs:
11+
package-macos:
12+
name: Package macOS app
13+
runs-on: macos-latest
14+
env:
15+
ORGANIZATION: ooni
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
20+
- name: Setup (repo action)
21+
uses: ./.github/actions/setup
22+
23+
- name: Cache Gradle
24+
uses: actions/cache@v4
25+
with:
26+
path: |
27+
~/.gradle/caches
28+
~/.gradle/wrapper
29+
key: ${{ runner.os }}-gradle-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}-${{ hashFiles('**/gradle.properties','**/*.gradle','**/*.gradle.kts') }}
30+
restore-keys: |
31+
${{ runner.os }}-gradle-
32+
33+
- name: Setup signing and notarization
34+
run: |
35+
echo "Details are not clear" # Placeholder for actual setup steps
36+
37+
- name: Package DMG
38+
run: ./gradlew copyBrandingToCommonResources packageDmg -Porganization=${{ env.ORGANIZATION }}
39+
40+
- name: Sparkle appcast generation
41+
run: ./gradlew generateSparkleAppCast -Porganization=${{ env.ORGANIZATION }}
42+
43+
- name: Upload artifacts
44+
uses: actions/upload-artifact@v4
45+
with:
46+
name: desktopApps-macos-${{ github.run_id }}
47+
path: |
48+
composeApp/build/compose/binaries/main/dmg/OONI Probe-*.dmg
49+
composeApp/build/compose/binaries/main/app/OONI Probe.app
50+
composeApp/macos-appcast.xml
51+
retention-days: 7
52+
53+
package-windows:
54+
name: Package Windows app
55+
runs-on: windows-latest
56+
env:
57+
ORGANIZATION: ooni
58+
steps:
59+
- name: Checkout
60+
uses: actions/checkout@v4
61+
62+
- name: Setup (repo action)
63+
uses: ./.github/actions/setup
64+
65+
- name: Cache Gradle
66+
uses: actions/cache@v4
67+
with:
68+
path: |
69+
%USERPROFILE%\\.gradle\\caches
70+
%USERPROFILE%\\.gradle\\wrapper
71+
key: ${{ runner.os }}-gradle-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}-${{ hashFiles('**/gradle.properties','**/*.gradle','**/*.gradle.kts') }}
72+
restore-keys: |
73+
${{ runner.os }}-gradle-
74+
75+
- name: Package Exe
76+
shell: pwsh
77+
run: .\gradlew.bat copyBrandingToCommonResources packageExe -Porganization=${{ env.ORGANIZATION }}
78+
79+
- name: Upload artifacts
80+
uses: actions/upload-artifact@v4
81+
with:
82+
name: desktopApps-windows-${{ github.run_id }}
83+
path: |
84+
composeApp/build/compose/binaries/main/exe/OONI Probe-*.exe
85+
retention-days: 7
86+
87+
package-linux:
88+
name: Package Linux app
89+
runs-on: ubuntu-latest
90+
env:
91+
ORGANIZATION: ooni
92+
steps:
93+
- name: Checkout
94+
uses: actions/checkout@v4
95+
96+
- name: Setup (repo action)
97+
uses: ./.github/actions/setup
98+
99+
- name: Cache Gradle
100+
uses: actions/cache@v4
101+
with:
102+
path: |
103+
~/.gradle/caches
104+
~/.gradle/wrapper
105+
key: ${{ runner.os }}-gradle-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}-${{ hashFiles('**/gradle.properties','**/*.gradle','**/*.gradle.kts') }}
106+
restore-keys: |
107+
${{ runner.os }}-gradle-
108+
109+
- name: Package Deb
110+
run: ./gradlew copyBrandingToCommonResources packageDeb -Porganization=${{ env.ORGANIZATION }}
111+
112+
- name: Install libfuse2
113+
run: |
114+
sudo add-apt-repository universe
115+
sudo apt-get update
116+
sudo apt-get install -y libfuse2
117+
118+
- name: Package AppImage
119+
run: ./gradlew copyBrandingToCommonResources packageAppImage -Porganization=${{ env.ORGANIZATION }}
120+
121+
- name: Upload artifacts
122+
uses: actions/upload-artifact@v4
123+
with:
124+
name: desktopApps-linux-${{ github.run_id }}
125+
path: |
126+
composeApp/build/compose/binaries/main/deb/ooni-probe_*_amd64.deb
127+
composeApp/build/compose/binaries/main/appimage-workspace/OONI-Probe-*-x86_64.AppImage
128+
retention-days: 7

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@ output
2525
composeApp/src/desktopMain/resources/windows/WinSparkle.*
2626

2727
/composeApp/src/desktopMain/frameworks/
28+
composeApp/macos-appcast.xml
2829

2930
certificates/*.pem

buildSrc/src/main/kotlin/TaskRegistration.kt

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
import ooni.appimage.PackageAppImageTask
2+
import ooni.sparkle.GenerateSparkleAppCastTask
3+
import ooni.sparkle.SetupSparkleTask
4+
import ooni.sparkle.WinSparkleSetupTask
15
import org.gradle.api.Project
26
import org.gradle.api.tasks.Exec
37
import org.gradle.api.tasks.JavaExec
48
import org.gradle.kotlin.dsl.register
59
import org.gradle.kotlin.dsl.withType
610
import java.io.File
7-
import kotlin.let
8-
import ooni.sparkle.SetupSparkleTask
9-
import ooni.sparkle.WinSparkleSetupTask
10-
import ooni.appimage.PackageAppImageTask
1111

1212
private fun isMac() = System.getProperty("os.name").lowercase().contains("mac")
1313

@@ -79,6 +79,19 @@ private fun Project.registerSparkleTask() {
7979
.orElse(layout.buildDirectory.dir("processedResources/desktop/main/macos/")),
8080
)
8181
}
82+
83+
tasks.register("generateSparkleAppCast", GenerateSparkleAppCastTask::class) {
84+
group = "setup"
85+
description = "Generates Sparkle appcast using the specified DMG file."
86+
onlyIf { isMac() }
87+
dependsOn("setupSparkle")
88+
89+
sparkleVersion.set(providers.gradleProperty("sparkleVersion").orElse("2.8.0"))
90+
edKeyFile.set(rootProject.file("certificates/sparkle_eddsa_private.pem"))
91+
appCastFile.set("macos-appcast.xml")
92+
downloadUrlPrefix.set("https://distribution.ooni.org")
93+
94+
}
8295
}
8396

8497
private fun Project.registerWinSparkleTask() {
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package ooni.sparkle
2+
3+
import org.gradle.api.DefaultTask
4+
import org.gradle.api.file.RegularFileProperty
5+
import org.gradle.api.provider.Property
6+
import org.gradle.api.tasks.Input
7+
import org.gradle.api.tasks.InputFile
8+
import org.gradle.api.tasks.TaskAction
9+
import org.gradle.process.ExecOperations
10+
import javax.inject.Inject
11+
12+
abstract class GenerateSparkleAppCastTask : DefaultTask() {
13+
@get:Inject
14+
abstract val execOperations: ExecOperations
15+
16+
@get:Input
17+
abstract val sparkleVersion: Property<String>
18+
19+
@get:InputFile
20+
abstract val edKeyFile: RegularFileProperty
21+
22+
@get:Input
23+
abstract val appCastFile: Property<String>
24+
25+
@get:Input
26+
abstract val downloadUrlPrefix: Property<String>
27+
28+
@TaskAction
29+
fun run() {
30+
val sparkleTool = sparkleVersion
31+
.map { project.layout.buildDirectory.file("sparkle/extracted-$it/bin/generate_appcast") }
32+
.get()
33+
34+
val dmgFile = project.file("build/compose/binaries/main/dmg")
35+
36+
val command = listOf(
37+
sparkleTool.get().asFile.absolutePath,
38+
"-o",
39+
appCastFile.get(),
40+
"--ed-key-file",
41+
edKeyFile.get().asFile.absolutePath,
42+
"--download-url-prefix",
43+
downloadUrlPrefix.get(),
44+
dmgFile.absolutePath
45+
)
46+
47+
project.logger.lifecycle("Running Sparkle generate_appcast with command: ${command.joinToString(" ")}")
48+
49+
execOperations.exec {
50+
commandLine(command)
51+
}.assertNormalExitValue()
52+
}
53+
}

docs/Release.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,8 @@ successfully and download the generated apps (zipped artifact).
135135

136136
##### 2.7.2 Sign windows app
137137

138-
We need to sign both the windows `.exe` and `.msix` files using our Extended Validation certificate.
139-
Follow the steps on our internal process to do so.
138+
- We need to sign the windows `.exe` file using our Extended Validation certificate. Follow the steps on our internal process to do so.
139+
- Generate the WinSparkle appcast for the signed `.exe` file.
140140

141141
#### 2.8 Create Release
142142

@@ -146,8 +146,7 @@ based on the new tag.
146146
**2.8.2** Write our manual release notes and add at the bottom the automatic changelog using the
147147
`Generate release notes` button.
148148

149-
**2.8.3** Upload all the desktop files downloaded during step *2.7.1*, except the `download.html`
150-
file, and swapping the windows `.exe` and `.msix` files for their signed versions (step *2.7.2*).
149+
**2.8.3** Upload all the desktop files downloaded during step *2.7.1*, and swapping the windows `.exe` files for their signed versions (step *2.7.2*).
151150

152151
**2.8.4** Publish release
153152

0 commit comments

Comments
 (0)