Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a "version" project setting and use it in new export presets #35555

Merged
merged 1 commit into from
Aug 4, 2023

Conversation

Calinou
Copy link
Member

@Calinou Calinou commented Jan 25, 2020

This makes it easy to retrieve the project version at runtime for display purposes, while simplifying the export preset configuration. You can now leave the version empty unless you need to override it on a per-preset basis.

Since export presets save the values of default values to the export_presets.cfg
file, this change only affects export presets created after this commit was merged.

The Android, iOS and macOS versions requirement have also been documented. See this Stack Overflow question.

August 2021 patch
From 0729050a714f84b9465a687acc9ed3d753924088 Mon Sep 17 00:00:00 2001
From: Hugo Locurcio <[email protected]>
Date: Sun, 22 Aug 2021 08:47:19 +0200
Subject: [PATCH] Add a "version" project setting, remove preset-specific
 version fields

This makes it easy to retrieve the project version at runtime
for display purposes, while simplifying the export preset configuration.
---
 core/config/project_settings.cpp          |  1 +
 doc/classes/ProjectSettings.xml           |  4 ++
 platform/android/export/export_plugin.cpp |  9 ++---
 platform/iphone/export/export_plugin.cpp  |  6 +--
 platform/osx/export/export_plugin.cpp     |  6 +--
 platform/windows/export/export_plugin.cpp | 46 +++++++++++++++--------
 6 files changed, 43 insertions(+), 29 deletions(-)

diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index c5e6c6d685633..2a9147e47650d 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1080,6 +1080,7 @@ ProjectSettings::ProjectSettings() {
 	GLOBAL_DEF_BASIC("application/config/name", "");
 	GLOBAL_DEF_BASIC("application/config/description", "");
 	custom_prop_info["application/config/description"] = PropertyInfo(Variant::STRING, "application/config/description", PROPERTY_HINT_MULTILINE_TEXT);
+	GLOBAL_DEF_BASIC("application/config/version", "1.0.0");
 	GLOBAL_DEF_BASIC("application/run/main_scene", "");
 	custom_prop_info["application/run/main_scene"] = PropertyInfo(Variant::STRING, "application/run/main_scene", PROPERTY_HINT_FILE, "*.tscn,*.scn,*.res");
 	GLOBAL_DEF("application/run/disable_stdout", false);
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 0d1fa0e70f7c6..fbd1459be0572 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -228,6 +228,10 @@
 		<member name="application/config/use_custom_user_dir" type="bool" setter="" getter="" default="false">
 			If [code]true[/code], the project will save user data to its own user directory (see [member application/config/custom_user_dir_name]). This setting is only effective on desktop platforms. A name must be set in the [member application/config/custom_user_dir_name] setting for this to take effect. If [code]false[/code], the project will save user data to [code](OS user data directory)/Godot/app_userdata/(project name)[/code].
 		</member>
+		<member name="application/config/version" type="String" setter="" getter="" default="&quot;1.0.0&quot;">
+			The project's human-readable version identifier. This should always be set to a non-empty string, as some exporters rely on this value being defined.
+			[b]Note:[/b] When exporting for iOS, this version number must be incremented every time a new version is submitted to the App Store, even if the previous version was rejected by Apple. For instance, version [code]1.2.3[/code] can be incremented to [code]1.2.4[/code], [code]1.3.0[/code] or [code]2.0.0[/code].
+		</member>
 		<member name="application/config/windows_native_icon" type="String" setter="" getter="" default="&quot;&quot;">
 			Icon set in [code].ico[/code] format used on Windows to set the game's icon. This is done automatically on start by calling [method DisplayServer.set_native_icon].
 		</member>
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 8ed2d4e60a540..f43d4f0b8883a 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -812,7 +812,7 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p
 	uint32_t string_table_ends = 0;
 	Vector<uint8_t> stable_extra;
 
-	String version_name = p_preset->get("version/name");
+	String version_name = GLOBAL_GET("application/config/version");
 	int version_code = p_preset->get("version/code");
 	String package_name = p_preset->get("package/unique_name");
 
@@ -1649,7 +1649,6 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
 	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), false));
 
 	r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1));
-	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0"));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname"));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true));
@@ -1795,7 +1794,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
 	String output;
 
 	bool remove_prev = p_preset->get("one_click_deploy/clear_previous_install");
-	String version_name = p_preset->get("version/name");
+	String version_name = GLOBAL_GET("application/config/version");
 	String package_name = p_preset->get("package/unique_name");
 
 	if (remove_prev) {
@@ -2515,7 +2514,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
 
 		String package_name = get_package_name(p_preset->get("package/unique_name"));
 		String version_code = itos(p_preset->get("version/code"));
-		String version_name = p_preset->get("version/name");
+		String version_name = GLOBAL_GET("application/config/version");
 		String enabled_abi_string = String("|").join(enabled_abis);
 		String sign_flag = should_sign ? "true" : "false";
 		String zipalign_flag = "true";
@@ -2684,7 +2683,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
 
 	String cmdline = p_preset->get("command_line/extra_args");
 
-	String version_name = p_preset->get("version/name");
+	String version_name = GLOBAL_GET("application/config/version");
 	String package_name = p_preset->get("package/unique_name");
 
 	String apk_expansion_pkey = p_preset->get("apk_expansion/public_key");
diff --git a/platform/iphone/export/export_plugin.cpp b/platform/iphone/export/export_plugin.cpp
index 69a8203e9f087..d544a0d4cc9a7 100644
--- a/platform/iphone/export/export_plugin.cpp
+++ b/platform/iphone/export/export_plugin.cpp
@@ -98,8 +98,6 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine"));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
-	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
-	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0"));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
 
 	Vector<PluginConfigIOS> found_plugins = get_plugins();
@@ -205,9 +203,9 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
 		} else if (lines[i].find("$bundle_identifier") != -1) {
 			strnew += lines[i].replace("$bundle_identifier", p_preset->get("application/bundle_identifier")) + "\n";
 		} else if (lines[i].find("$short_version") != -1) {
-			strnew += lines[i].replace("$short_version", p_preset->get("application/short_version")) + "\n";
+			strnew += lines[i].replace("$short_version", GLOBAL_GET("application/config/version")) + "\n";
 		} else if (lines[i].find("$version") != -1) {
-			strnew += lines[i].replace("$version", p_preset->get("application/version")) + "\n";
+			strnew += lines[i].replace("$version", GLOBAL_GET("application/config/version")) + "\n";
 		} else if (lines[i].find("$signature") != -1) {
 			strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n";
 		} else if (lines[i].find("$copyright") != -1) {
diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp
index 5b959d6da455c..00e59412bf4e2 100644
--- a/platform/osx/export/export_plugin.cpp
+++ b/platform/osx/export/export_plugin.cpp
@@ -54,8 +54,6 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_category", PROPERTY_HINT_ENUM, "Business,Developer-tools,Education,Entertainment,Finance,Games,Action-games,Adventure-games,Arcade-games,Board-games,Card-games,Casino-games,Dice-games,Educational-games,Family-games,Kids-games,Music-games,Puzzle-games,Racing-games,Role-playing-games,Simulation-games,Sports-games,Strategy-games,Trivia-games,Word-games,Graphics-design,Healthcare-fitness,Lifestyle,Medical,Music,News,Photography,Productivity,Reference,Social-networking,Sports,Travel,Utilities,Video,Weather"), "Games"));
-	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
-	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0"));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), false));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the camera"), ""));
@@ -293,9 +291,9 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset
 		} else if (lines[i].find("$bundle_identifier") != -1) {
 			strnew += lines[i].replace("$bundle_identifier", p_preset->get("application/bundle_identifier")) + "\n";
 		} else if (lines[i].find("$short_version") != -1) {
-			strnew += lines[i].replace("$short_version", p_preset->get("application/short_version")) + "\n";
+			strnew += lines[i].replace("$short_version", GLOBAL_GET("application/config/version")) + "\n";
 		} else if (lines[i].find("$version") != -1) {
-			strnew += lines[i].replace("$version", p_preset->get("application/version")) + "\n";
+			strnew += lines[i].replace("$version", GLOBAL_GET("application/config/version")) + "\n";
 		} else if (lines[i].find("$signature") != -1) {
 			strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n";
 		} else if (lines[i].find("$app_category") != -1) {
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index 165e86c066c5c..5c784b0500a39 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -70,8 +70,6 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
 	r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
 
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico"), ""));
-	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0"), ""));
-	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), ""));
@@ -92,28 +90,44 @@ void EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset>
 	}
 
 #ifndef WINDOWS_ENABLED
-	// On non-Windows we need WINE to run rcedit
+	// On non-Windows platforms, we need Wine to run rcedit.
 	String wine_path = EditorSettings::get_singleton()->get("export/windows/wine");
 
 	if (wine_path != String() && !FileAccess::exists(wine_path)) {
-		ERR_PRINT("Could not find wine executable at " + wine_path + ", no icon or app information data will be included.");
+		ERR_PRINT("Could not find Wine executable at " + wine_path + ". No icon or app information data will be included.");
 		return;
 	}
 
 	if (wine_path == String()) {
-		wine_path = "wine"; // try to run wine from PATH
+		// Try to run Wine from the `PATH`.
+		wine_path = "wine";
 	}
 #endif
 
-	String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon"));
-	String file_verion = p_preset->get("application/file_version");
-	String product_version = p_preset->get("application/product_version");
-	String company_name = p_preset->get("application/company_name");
-	String product_name = p_preset->get("application/product_name");
-	String file_description = p_preset->get("application/file_description");
-	String copyright = p_preset->get("application/copyright");
-	String trademarks = p_preset->get("application/trademarks");
-	String comments = p_preset->get("application/comments");
+	const String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon"));
+
+	// Use `x.y.z.w` format on the version string as required by Microsoft.
+	const String version = GLOBAL_GET("application/config/version");
+	const PackedStringArray version_split = version.split(".");
+	String file_version;
+	if (version_split.size() <= 1) {
+		file_version = version + ".0.0.0";
+	} else if (version_split.size() == 2) {
+		file_version = version + ".0.0";
+	} else if (version_split.size() == 3) {
+		file_version = version + ".0";
+	} else {
+		// 4 components or more in the version string. Trim to contain only the first 4 components.
+		file_version = vformat("%s.%s.%s.%s", version_split[0] + version_split[1] + version_split[2] + version_split[3]);
+	};
+	const String product_version = file_version;
+
+	const String company_name = p_preset->get("application/company_name");
+	const String product_name = p_preset->get("application/product_name");
+	const String file_description = p_preset->get("application/file_description");
+	const String copyright = p_preset->get("application/copyright");
+	const String trademarks = p_preset->get("application/trademarks");
+	const String comments = p_preset->get("application/comments");
 
 	List<String> args;
 	args.push_back(p_path);
@@ -121,9 +135,9 @@ void EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset>
 		args.push_back("--set-icon");
 		args.push_back(icon_path);
 	}
-	if (file_verion != String()) {
+	if (file_version != String()) {
 		args.push_back("--set-file-version");
-		args.push_back(file_verion);
+		args.push_back(file_version);
 	}
 	if (product_version != String()) {
 		args.push_back("--set-product-version");

@Calinou Calinou requested a review from a team as a code owner January 25, 2020 17:40
@Calinou Calinou added this to the 4.0 milestone Jan 25, 2020
@Calinou Calinou force-pushed the add-version-project-setting branch from 27a03c6 to 76f8929 Compare January 25, 2020 17:41
@aaronfranke
Copy link
Member

@Calinou Is this still desired? If so, this needs to be rebased against the latest master branch.

@Calinou Calinou force-pushed the add-version-project-setting branch from fa0de0e to 0e247ff Compare August 22, 2021 06:56
@Calinou Calinou requested review from a team as code owners August 22, 2021 06:56
@Calinou
Copy link
Member Author

Calinou commented Aug 22, 2021

Rebased. In the Windows export code, I also added version conversion logic required for rcedit to work if your version string does not follow the format x.y.z.w.

@Calinou Calinou force-pushed the add-version-project-setting branch from 0e247ff to 0729050 Compare August 22, 2021 06:57
@@ -228,6 +228,10 @@
<member name="application/config/use_custom_user_dir" type="bool" setter="" getter="" default="false">
If [code]true[/code], the project will save user data to its own user directory (see [member application/config/custom_user_dir_name]). This setting is only effective on desktop platforms. A name must be set in the [member application/config/custom_user_dir_name] setting for this to take effect. If [code]false[/code], the project will save user data to [code](OS user data directory)/Godot/app_userdata/(project name)[/code].
</member>
<member name="application/config/version" type="String" setter="" getter="" default="&quot;1.0.0&quot;">
The project's human-readable version identifier. This should always be set to a non-empty string, as some exporters rely on this value being defined.
[b]Note:[/b] When exporting for iOS, this version number must be incremented every time a new version is submitted to the App Store, even if the previous version was rejected by Apple. For instance, version [code]1.2.3[/code] can be incremented to [code]1.2.4[/code], [code]1.3.0[/code] or [code]2.0.0[/code].
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not entirely correct.
If submitted application gets rejected it's enough to change/increase CFBundleVersion. This value doesn't get displayed to user on AppStore, CFBundleShortVersionString does.
In most cases CFBundleVersion is used as build number, so displaying application version like CFBundleShortVersionString (CFBundleVersion) results in something like 1.0.0 (2520). And on TestFlight builds are grouped by CFBundleShortVersionString value.

} else if (lines[i].find("$version") != -1) {
strnew += lines[i].replace("$version", p_preset->get("application/version")) + "\n";
strnew += lines[i].replace("$version", GLOBAL_GET("application/config/version")) + "\n";
Copy link
Contributor

@naithar naithar Aug 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think only $short_version (CFBundleShortVersionString) should be replaced with application/config/version.
$version (CFBundleVersion) which is internal application version would be better to stay as export setting.

In some cases if CFBundleShortVersionString get's changed (which it should after every release) there might be no reason to change CFBundleVersion so it can stay the same. But it should be changed in case of AppStore rejection, so the version displayed in AppStore does not get increased without a reason.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the ideal case here is to have version kept in the export setting, while having an empty value default to the short_version one.

@mhilbrunner
Copy link
Member

mhilbrunner commented Aug 23, 2021

This could be useful to check if other network peers are running the same project version for compatibility purposes as well.
I'd like to have this. :)

@KoBeWi
Copy link
Member

KoBeWi commented Dec 3, 2021

Kind of reminds me of godotengine/godot-proposals#228
I mean it's nice to have a single version string that will be used by any preset. But the problem I outlined in my proposal isn't specific only to version and resolving it would make the export changes in this PR less relevant.

As for easy retrieving of the version string, this is doable with a plugin, as I commented here: godotengine/godot-proposals#372 (comment)
I'm going to put a similar plugin to AssetLib eventually.

@@ -1649,7 +1649,6 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), false));

r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Calinou I'm wondering if it would be better to keep this property and have it default to application/config/version.
The advantage of keeping is that it allows you to customize the version string per export preset (for example, you could have one Android export preset that support VR and another one that doesn't for the same game, and this would allow to update their version name accordingly).

@YuriSizov
Copy link
Contributor

Needs a rebase and to address the feedback, but otherwise we should include this for 4.0!

@YuriSizov YuriSizov modified the milestones: 4.0, 4.1 Feb 10, 2023
@YuriSizov YuriSizov modified the milestones: 4.1, 4.2 Jun 14, 2023
@Calinou Calinou force-pushed the add-version-project-setting branch from 0729050 to 557bcc0 Compare July 17, 2023 07:58
@Calinou Calinou changed the title Add a "version" project setting, remove preset-specific version fields Add a "version" project setting and use it in new export presets Jul 17, 2023
@Calinou Calinou requested a review from m4gr3d July 17, 2023 07:59
@Calinou
Copy link
Member Author

Calinou commented Jul 17, 2023

Needs a rebase and to address the feedback, but otherwise we should include this for 4.0!

I've revamped this PR in a way that preserves the ability to override versions on a per-preset basis. See OP for an updated description.

Note that I haven't tested these changes yet.

Copy link
Contributor

@m4gr3d m4gr3d left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look good!

@YuriSizov
Copy link
Contributor

Documentation needs fixing the order :)

@Calinou Calinou force-pushed the add-version-project-setting branch from 557bcc0 to 101c911 Compare July 18, 2023 20:10
@akien-mga akien-mga requested a review from bruvzg August 2, 2023 08:58
Copy link
Member

@bruvzg bruvzg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems fine.

@Calinou Calinou force-pushed the add-version-project-setting branch from 101c911 to f033962 Compare August 3, 2023 01:04
@Calinou Calinou force-pushed the add-version-project-setting branch from f033962 to eb16ffe Compare August 4, 2023 00:17
This makes it easy to retrieve the project version at runtime
for display purposes, while simplifying the export preset configuration.
You can now leave the version empty unless you need to override it on a per-preset
basis.

Since export presets save the values of default values to the `export_presets.cfg`
file, this change only affects export presets created after this commit was merged.
@Calinou Calinou force-pushed the add-version-project-setting branch from eb16ffe to ad4480b Compare August 4, 2023 08:29
Copy link
Member

@akien-mga akien-mga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems OK.

I'm slightly concerned about the UX since we now have a mostly mandatory project setting which is empty by default, but which can be overridden in presets - but the placeholders advise to leave it empty, without clarifying whether there is a valid fallback for them to use.

Let's see how it goes, we could add more validation code if needed.

@YuriSizov YuriSizov merged commit dc6ea03 into godotengine:master Aug 4, 2023
@YuriSizov
Copy link
Contributor

Thanks!

@Calinou
Copy link
Member Author

Calinou commented Aug 4, 2023

I'm slightly concerned about the UX since we now have a mostly mandatory project setting which is empty by default

I thought I had set its default to 1.0.0. I guess I forgot to do that. Can I do that in a follow-up PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add function to get exported application version / product version
10 participants