Skip to content

Commit 099a86c

Browse files
authored
Merge pull request #2958 from wgqqqqq/wgq/fix-beta-market-compatibility
fix(release): allow 1.0.0-beta to install marketplace packages
2 parents 4b91d77 + f0275e6 commit 099a86c

5 files changed

Lines changed: 63 additions & 9 deletions

File tree

‎docs/development/releasing.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,9 @@ For release workflow and channel-isolation changes, run
134134
`node --test scripts/relay/package-contract.test.mjs scripts/tauri-release-manifest.test.mjs`.
135135
These checks exercise release conditions, image tag selection, Beta manifest
136136
generation, and asset collection with fixtures; they do not build or publish packages.
137+
138+
The inaugural public `1.0.0-beta` release supports marketplace packages declaring
139+
minimum OpenBitFun `1.0.0`. This is an explicit product compatibility exception;
140+
numbered beta and RC builds retain their normal SemVer ordering, and updater
141+
version comparisons are unchanged. Requirements above `1.0.0` still reject this
142+
release. The shared policy lives in `product-domains::product_release`.

‎src/apps/cli/tests/terminal_process_contracts.rs‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ const EXEC_STREAM_SIZE: PtySize = PtySize {
3131
const STARTUP_INPUT: &[u8] = b"exercise active turn resize Q7Z9";
3232
const STARTUP_INPUT_SENTINEL: &str = "Q7Z9";
3333
const MULTILINE_INPUT_SENTINEL: &str = "M7Q4";
34+
// Must not match the product version in the startup header (for example beta).
35+
const MULTILINE_TAIL_SENTINEL: &str = "Z9R2";
3436
const RECOVERY_INPUT: &[u8] = b"READY_AFTER_CANCEL K4W8";
3537
const RECOVERY_INPUT_SENTINEL: &str = "K4W8";
3638

@@ -117,12 +119,16 @@ fn interactive_startup_survives_resize_multiline_input_and_emits_cleanup() {
117119
// Ratatui emits only changed cells, so the sentinel must not share characters
118120
// with the startup placeholder at the same screen positions.
119121
#[cfg(unix)]
120-
process.write(b"\x1b[200~M7Q4\r\nbeta\x1b[201~");
122+
process.write(
123+
format!("\x1b[200~{MULTILINE_INPUT_SENTINEL}\r\n{MULTILINE_TAIL_SENTINEL}\x1b[201~")
124+
.as_bytes(),
125+
);
121126
#[cfg(windows)]
122127
{
123128
let mut rapid_input = MULTILINE_INPUT_SENTINEL.as_bytes().to_vec();
124129
rapid_input.extend(std::iter::repeat_n(b'a', 251));
125-
rapid_input.extend_from_slice(b"\rbeta");
130+
rapid_input.push(b'\r');
131+
rapid_input.extend_from_slice(MULTILINE_TAIL_SENTINEL.as_bytes());
126132
process.write(&rapid_input);
127133
}
128134

@@ -132,7 +138,7 @@ fn interactive_startup_survives_resize_multiline_input_and_emits_cleanup() {
132138
"interactive startup did not render multiline input",
133139
);
134140
process.expect_output(
135-
"beta",
141+
MULTILINE_TAIL_SENTINEL,
136142
Duration::from_secs(15),
137143
"interactive startup did not render the multiline input tail",
138144
);
@@ -152,7 +158,7 @@ fn interactive_startup_survives_resize_multiline_input_and_emits_cleanup() {
152158
"paste text was not rendered:\n{output}"
153159
);
154160
assert!(
155-
output.contains("beta"),
161+
output.contains(MULTILINE_TAIL_SENTINEL),
156162
"paste tail was not rendered:\n{output}"
157163
);
158164
assert!(

‎src/apps/desktop/src/api/appearance_market_api.rs‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ use openbitfun_product_domains::appearance_market::{
1414
AppearanceMarketSubmissionStatus, AppearanceReviewDecision, AppearanceReviewDecisionRequest,
1515
APPEARANCE_MARKET_MAX_PACKAGE_BYTES,
1616
};
17-
use openbitfun_product_domains::product_release::OPENBITFUN_INITIAL_RELEASE_VERSION;
17+
use openbitfun_product_domains::product_release::{
18+
supports_market_minimum_version, OPENBITFUN_INITIAL_RELEASE_VERSION,
19+
};
1820
use openbitfun_services_integrations::appearance_market::{
1921
resolve_appearance_release_target, submit_appearance_package, suggest_appearance_slug,
2022
AppearanceMarketBrowseRequest, AppearanceMarketClient, AppearanceReleaseTarget,
@@ -358,7 +360,7 @@ fn validate_minimum_openbitfun_version(minimum: &str) -> Result<(), String> {
358360
}
359361
let current = semver::Version::parse(env!("CARGO_PKG_VERSION"))
360362
.map_err(|_| "The current OpenBitFun version is invalid.".to_string())?;
361-
if current < minimum {
363+
if !supports_market_minimum_version(&current, &minimum) {
362364
return Err(format!(
363365
"This Appearance requires OpenBitFun {minimum} or newer. Current version: {current}."
364366
));

‎src/apps/desktop/src/api/miniapp_market_api.rs‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ use openbitfun_product_domains::miniapp::market::{
1515
CursorPage, InstalledMarketOrigin, MarketListingDetail, MarketListingSummary, MarketRelease,
1616
MarketSubmission, MarketSubmissionDraftRequest,
1717
};
18-
use openbitfun_product_domains::product_release::OPENBITFUN_INITIAL_RELEASE_VERSION;
18+
use openbitfun_product_domains::product_release::{
19+
supports_market_minimum_version, OPENBITFUN_INITIAL_RELEASE_VERSION,
20+
};
1921
use openbitfun_services_integrations::miniapp_market::{
2022
submit_installed_app, validate_market_package, FavoriteAggregate, MarketBrowseRequest,
2123
MarketClient, RatingAggregate, ValidatedMarketPackage,
@@ -676,7 +678,7 @@ fn validate_minimum_openbitfun_version(minimum: &str) -> Result<(), String> {
676678
}
677679
let current = semver::Version::parse(env!("CARGO_PKG_VERSION"))
678680
.map_err(|_| "The current OpenBitFun version is invalid.".to_string())?;
679-
if current < minimum {
681+
if !supports_market_minimum_version(&current, &minimum) {
680682
return Err(format!(
681683
"This MiniApp requires OpenBitFun {minimum} or newer. Current version: {current}."
682684
));

‎src/crates/contracts/product-domains/src/product_release.rs‎

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,47 @@ use semver::Version;
55
/// OpenBitFun begins as a new product at this release.
66
pub const OPENBITFUN_INITIAL_RELEASE_VERSION: Version = Version::new(1, 0, 0);
77

8+
/// Market packages use stable product compatibility versions. The inaugural
9+
/// public release is named `1.0.0-beta`, but supports the 1.0.0 market contract.
10+
/// Keep this exception separate from updater SemVer ordering and from numbered
11+
/// beta / release-candidate builds, which retain normal prerelease semantics.
12+
pub fn supports_market_minimum_version(current: &Version, minimum: &Version) -> bool {
13+
current >= minimum
14+
|| (current.major == 1
15+
&& current.minor == 0
16+
&& current.patch == 0
17+
&& current.pre.as_str() == "beta"
18+
&& minimum == &OPENBITFUN_INITIAL_RELEASE_VERSION)
19+
}
20+
821
#[cfg(test)]
922
mod tests {
10-
use super::OPENBITFUN_INITIAL_RELEASE_VERSION;
23+
use super::*;
24+
25+
#[test]
26+
fn inaugural_beta_supports_stable_market_contract_only() {
27+
let initial = &OPENBITFUN_INITIAL_RELEASE_VERSION;
28+
let beta = Version::parse("1.0.0-beta").unwrap();
29+
assert!(supports_market_minimum_version(&beta, initial));
30+
assert!(!supports_market_minimum_version(
31+
&beta,
32+
&Version::new(1, 0, 1)
33+
));
34+
for version in ["0.2.19", "1.0.0-beta.1", "1.0.0-rc.1"] {
35+
assert!(!supports_market_minimum_version(
36+
&Version::parse(version).unwrap(),
37+
initial
38+
));
39+
}
40+
assert!(supports_market_minimum_version(
41+
&Version::new(1, 0, 0),
42+
initial
43+
));
44+
assert!(supports_market_minimum_version(
45+
&Version::new(1, 1, 0),
46+
initial
47+
));
48+
}
1149

1250
#[test]
1351
fn initial_release_is_stable_one_zero_zero() {

0 commit comments

Comments
 (0)