Introduce a build setting to detect Nightly builds. (#5852)

* Allow the AppIconBanner tool to be called with purely the build number.

And use that for the Element Pro Nightly.

* Use a build setting to determine Nightly builds.
This commit is contained in:
Doug
2026-07-09 13:56:26 +01:00
committed by GitHub
parent 5ba9296a65
commit 5915713a02
16 changed files with 43 additions and 16 deletions
+2
View File
@@ -9880,6 +9880,7 @@
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 18.5; IPHONEOS_DEPLOYMENT_TARGET = 18.5;
IS_NIGHTLY_BUILD = NO;
KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(DEVELOPMENT_TEAM).$(BASE_BUNDLE_IDENTIFIER)"; KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(DEVELOPMENT_TEAM).$(BASE_BUNDLE_IDENTIFIER)";
MACOSX_DEPLOYMENT_TARGET = 14.5; MACOSX_DEPLOYMENT_TARGET = 14.5;
MARKETING_VERSION = 26.07.3; MARKETING_VERSION = 26.07.3;
@@ -9960,6 +9961,7 @@
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 18.5; IPHONEOS_DEPLOYMENT_TARGET = 18.5;
IS_NIGHTLY_BUILD = NO;
KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(DEVELOPMENT_TEAM).$(BASE_BUNDLE_IDENTIFIER)"; KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(DEVELOPMENT_TEAM).$(BASE_BUNDLE_IDENTIFIER)";
MACOSX_DEPLOYMENT_TARGET = 14.5; MACOSX_DEPLOYMENT_TARGET = 14.5;
MARKETING_VERSION = 26.07.3; MARKETING_VERSION = 26.07.3;
@@ -40,11 +40,10 @@ nonisolated enum AppBuildType {
#if DEBUG #if DEBUG
return .debug return .debug
#else #else
switch InfoPlistReader.main.baseBundleIdentifier { if InfoPlistReader.main.isNightlyBuild {
case "io.element.elementx.nightly": .nightly
return .nightly } else {
default: .release
return .release
} }
#endif #endif
} }
+12 -1
View File
@@ -16,6 +16,7 @@ nonisolated struct InfoPlistReader {
static let bundleShortVersion = "CFBundleShortVersionString" static let bundleShortVersion = "CFBundleShortVersionString"
static let bundleDisplayName = "CFBundleDisplayName" static let bundleDisplayName = "CFBundleDisplayName"
static let productionAppName = "productionAppName" static let productionAppName = "productionAppName"
static let isNightlyBuild = "isNightlyBuild"
static let utExportedTypeDeclarationsKey = "UTExportedTypeDeclarations" static let utExportedTypeDeclarationsKey = "UTExportedTypeDeclarations"
static let utTypeIdentifierKey = "UTTypeIdentifier" static let utTypeIdentifierKey = "UTTypeIdentifier"
static let utDescriptionKey = "UTTypeDescription" static let utDescriptionKey = "UTTypeDescription"
@@ -93,6 +94,11 @@ nonisolated struct InfoPlistReader {
infoPlistValue(forKey: Keys.productionAppName) infoPlistValue(forKey: Keys.productionAppName)
} }
/// Whether or not the build is from the Nightly stream.
var isNightlyBuild: Bool {
infoPlistValue(forKey: Keys.isNightlyBuild)
}
// MARK: - Custom App Scheme // MARK: - Custom App Scheme
var appScheme: String { var appScheme: String {
@@ -144,7 +150,7 @@ nonisolated struct InfoPlistReader {
@_disfavoredOverload // Make sure optional types default to the optional version below. @_disfavoredOverload // Make sure optional types default to the optional version below.
private func infoPlistValue<T>(forKey key: String) -> T { private func infoPlistValue<T>(forKey key: String) -> T {
guard let result = bundle.object(forInfoDictionaryKey: key) as? T else { guard let result = bundle.object(forInfoDictionaryKey: key) as? T else {
fatalError("Add \(key) into your target's Info.plst") fatalError("Add \(key) into your target's Info.plist")
} }
return result return result
} }
@@ -153,6 +159,11 @@ nonisolated struct InfoPlistReader {
bundle.object(forInfoDictionaryKey: key) as? T bundle.object(forInfoDictionaryKey: key) as? T
} }
private func infoPlistValue(forKey key: String) -> Bool {
// Build setting values are stored as strings ("YES"/"NO")…
(infoPlistValue(forKey: key) as NSString).boolValue
}
private func customSchemeForName(_ name: String) -> String { private func customSchemeForName(_ name: String) -> String {
let urlTypes: [[String: Any]] = infoPlistValue(forKey: Keys.bundleURLTypes) let urlTypes: [[String: Any]] = infoPlistValue(forKey: Keys.bundleURLTypes)
@@ -88,7 +88,7 @@ class BugReportService: NSObject, BugReportServiceProtocol {
params.append(contentsOf: defaultParams) params.append(contentsOf: defaultParams)
if InfoPlistReader.main.baseBundleIdentifier == "io.element.elementx.nightly" { if AppBuildType.current == .nightly {
bugReport.githubLabels.append("Nightly") bugReport.githubLabels.append("Nightly")
} }
+2
View File
@@ -122,6 +122,8 @@
<string>$(CLASSIC_APP_KEYCHAIN_ACCESS_GROUP_IDENTIFIER)</string> <string>$(CLASSIC_APP_KEYCHAIN_ACCESS_GROUP_IDENTIFIER)</string>
<key>classicAppKeychainServiceIdentifier</key> <key>classicAppKeychainServiceIdentifier</key>
<string>$(CLASSIC_APP_KEYCHAIN_SERVICE_IDENTIFIER)</string> <string>$(CLASSIC_APP_KEYCHAIN_SERVICE_IDENTIFIER)</string>
<key>isNightlyBuild</key>
<string>$(IS_NIGHTLY_BUILD)</string>
<key>keychainAccessGroupIdentifier</key> <key>keychainAccessGroupIdentifier</key>
<string>$(KEYCHAIN_ACCESS_GROUP_IDENTIFIER)</string> <string>$(KEYCHAIN_ACCESS_GROUP_IDENTIFIER)</string>
<key>productionAppName</key> <key>productionAppName</key>
+1
View File
@@ -77,6 +77,7 @@ targets:
classicAppKeychainAccessGroupIdentifier: $(CLASSIC_APP_KEYCHAIN_ACCESS_GROUP_IDENTIFIER) classicAppKeychainAccessGroupIdentifier: $(CLASSIC_APP_KEYCHAIN_ACCESS_GROUP_IDENTIFIER)
classicAppDeepLinkURL: $(CLASSIC_APP_DEEP_LINK_URL) classicAppDeepLinkURL: $(CLASSIC_APP_DEEP_LINK_URL)
productionAppName: $(PRODUCTION_APP_NAME) productionAppName: $(PRODUCTION_APP_NAME)
isNightlyBuild: $(IS_NIGHTLY_BUILD)
ITSAppUsesNonExemptEncryption: false ITSAppUsesNonExemptEncryption: false
NSUserActivityTypes: [ NSUserActivityTypes: [
INSendMessageIntent, INSendMessageIntent,
+2
View File
@@ -31,6 +31,8 @@
<string>$(APP_GROUP_IDENTIFIER)</string> <string>$(APP_GROUP_IDENTIFIER)</string>
<key>baseBundleIdentifier</key> <key>baseBundleIdentifier</key>
<string>$(BASE_BUNDLE_IDENTIFIER)</string> <string>$(BASE_BUNDLE_IDENTIFIER)</string>
<key>isNightlyBuild</key>
<string>$(IS_NIGHTLY_BUILD)</string>
<key>keychainAccessGroupIdentifier</key> <key>keychainAccessGroupIdentifier</key>
<string>$(KEYCHAIN_ACCESS_GROUP_IDENTIFIER)</string> <string>$(KEYCHAIN_ACCESS_GROUP_IDENTIFIER)</string>
<key>productionAppName</key> <key>productionAppName</key>
+1
View File
@@ -54,6 +54,7 @@ targets:
baseBundleIdentifier: $(BASE_BUNDLE_IDENTIFIER) baseBundleIdentifier: $(BASE_BUNDLE_IDENTIFIER)
keychainAccessGroupIdentifier: $(KEYCHAIN_ACCESS_GROUP_IDENTIFIER) keychainAccessGroupIdentifier: $(KEYCHAIN_ACCESS_GROUP_IDENTIFIER)
productionAppName: $(PRODUCTION_APP_NAME) productionAppName: $(PRODUCTION_APP_NAME)
isNightlyBuild: $(IS_NIGHTLY_BUILD)
NSExtension: NSExtension:
NSExtensionPointIdentifier: com.apple.usernotifications.service NSExtensionPointIdentifier: com.apple.usernotifications.service
NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).NotificationServiceExtension NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).NotificationServiceExtension
@@ -51,6 +51,8 @@
<string>$(APP_GROUP_IDENTIFIER)</string> <string>$(APP_GROUP_IDENTIFIER)</string>
<key>baseBundleIdentifier</key> <key>baseBundleIdentifier</key>
<string>$(BASE_BUNDLE_IDENTIFIER)</string> <string>$(BASE_BUNDLE_IDENTIFIER)</string>
<key>isNightlyBuild</key>
<string>$(IS_NIGHTLY_BUILD)</string>
<key>keychainAccessGroupIdentifier</key> <key>keychainAccessGroupIdentifier</key>
<string>$(KEYCHAIN_ACCESS_GROUP_IDENTIFIER)</string> <string>$(KEYCHAIN_ACCESS_GROUP_IDENTIFIER)</string>
<key>productionAppName</key> <key>productionAppName</key>
@@ -49,6 +49,7 @@ targets:
baseBundleIdentifier: $(BASE_BUNDLE_IDENTIFIER) baseBundleIdentifier: $(BASE_BUNDLE_IDENTIFIER)
keychainAccessGroupIdentifier: $(KEYCHAIN_ACCESS_GROUP_IDENTIFIER) keychainAccessGroupIdentifier: $(KEYCHAIN_ACCESS_GROUP_IDENTIFIER)
productionAppName: $(PRODUCTION_APP_NAME) productionAppName: $(PRODUCTION_APP_NAME)
isNightlyBuild: $(IS_NIGHTLY_BUILD)
NSExtension: NSExtension:
NSExtensionPointIdentifier: com.apple.share-services NSExtensionPointIdentifier: com.apple.share-services
NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).ShareExtensionViewController NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).ShareExtensionViewController
+5 -2
View File
@@ -7,8 +7,8 @@ struct AppIconBanner: AsyncParsableCommand {
@Argument(help: "Path to the input image.") @Argument(help: "Path to the input image.")
var path: String var path: String
@Option(help: "Text for the banner.") @Option(help: "The build number appended to the app's version.")
var bannerText: String var buildNumber: Int
@MainActor @MainActor
func run() async throws { func run() async throws {
@@ -19,6 +19,9 @@ struct AppIconBanner: AsyncParsableCommand {
throw ValidationError("Could not load the image at \(pathURL).") throw ValidationError("Could not load the image at \(pathURL).")
} }
let version = try CI.readMarketingVersion()
let bannerText = "\(version) (\(buildNumber))"
let renderer = ImageRenderer(content: BannerImage(image: image, let renderer = ImageRenderer(content: BannerImage(image: image,
text: bannerText)) text: bannerText))
@@ -19,8 +19,7 @@ struct ConfigureNightly: AsyncParsableCommand {
try await CI.run(.name("swift"), ["run", "pipeline", "update-foss-secrets"]) try await CI.run(.name("swift"), ["run", "pipeline", "update-foss-secrets"])
try await CI.run(.name("xcodegen")) try await CI.run(.name("xcodegen"))
let releaseVersion = try CI.readMarketingVersion() try await generateAppIconBanner(buildNumber: buildNumber)
try await generateAppIconBanner(version: releaseVersion, buildNumber: buildNumber)
} }
/// Adds the Nightly variant include path to `project.yml` if it isn't already present. /// Adds the Nightly variant include path to `project.yml` if it isn't already present.
@@ -41,9 +40,8 @@ struct ConfigureNightly: AsyncParsableCommand {
} }
/// Generates the app icon banner with version and build number. /// Generates the app icon banner with version and build number.
private func generateAppIconBanner(version: String, buildNumber: String) async throws { private func generateAppIconBanner(buildNumber: String) async throws {
let bannerText = "\(version) (\(buildNumber))"
let iconPath = "Variants/Nightly/Resources/NightlyAppIcon.icon/Assets/Version.png" let iconPath = "Variants/Nightly/Resources/NightlyAppIcon.icon/Assets/Version.png"
try await AppIconBanner.parse([iconPath, "--banner-text", bannerText]).run() try await AppIconBanner.parse([iconPath, "--build-number", buildNumber]).run()
} }
} }
+1
View File
@@ -1,6 +1,7 @@
settings: settings:
APP_GROUP_IDENTIFIER: group.io.element.nightly APP_GROUP_IDENTIFIER: group.io.element.nightly
BASE_BUNDLE_IDENTIFIER: io.element.elementx.nightly BASE_BUNDLE_IDENTIFIER: io.element.elementx.nightly
IS_NIGHTLY_BUILD: true
targets: targets:
ElementX: ElementX:
+1
View File
@@ -5,6 +5,7 @@ settings:
BASE_BUNDLE_IDENTIFIER: io.element.elementx BASE_BUNDLE_IDENTIFIER: io.element.elementx
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: "colors/accent-color" ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: "colors/accent-color"
DEVELOPMENT_TEAM: 7J4U792NQT DEVELOPMENT_TEAM: 7J4U792NQT
IS_NIGHTLY_BUILD: false
# Optional configuration to load accounts from Element Classic. # Optional configuration to load accounts from Element Classic.
CLASSIC_APP_GROUP_IDENTIFIER: group.im.vector CLASSIC_APP_GROUP_IDENTIFIER: group.im.vector
+3
View File
@@ -12,6 +12,9 @@ if [ "$CI_WORKFLOW" = "Nightly" ]; then
elif [ "$CI_WORKFLOW" = "Element Pro" ]; then elif [ "$CI_WORKFLOW" = "Element Pro" ]; then
# Xcode Cloud automatically fetches the submodules. # Xcode Cloud automatically fetches the submodules.
swift run pipeline configure-element-pro swift run pipeline configure-element-pro
elif [ "$CI_WORKFLOW" = "Element Pro Nightly" ]; then
# Xcode Cloud automatically fetches the submodules.
swift run pipeline configure-element-pro-nightly --build-number $CI_BUILD_NUMBER
else else
swift run tools ci configure-production swift run tools ci configure-production
fi fi