diff --git a/content/learn/migration-guides/0.10-to-0.11.md b/content/learn/migration-guides/0.10-to-0.11.md
index 8d90ade691..59ee0cf065 100644
--- a/content/learn/migration-guides/0.10-to-0.11.md
+++ b/content/learn/migration-guides/0.10-to-0.11.md
@@ -9,7 +9,7 @@ weight = 6
Bevy relies heavily on improvements in the Rust language and compiler.
As a result, the Minimum Supported Rust Version (MSRV) is "the latest stable release" of Rust.
-
+
### [Schedule-First: the new and improved add_systems](https://github.com/bevyengine/bevy/pull/8079)
diff --git a/content/learn/migration-guides/0.11-to-0.12.md b/content/learn/migration-guides/0.11-to-0.12.md
index be9e50592a..7f16155acc 100644
--- a/content/learn/migration-guides/0.11-to-0.12.md
+++ b/content/learn/migration-guides/0.11-to-0.12.md
@@ -9,7 +9,7 @@ weight = 7
Bevy relies heavily on improvements in the Rust language and compiler.
As a result, the Minimum Supported Rust Version (MSRV) is "the latest stable release" of Rust.
-
+
### [API updates to the AnimationPlayer](https://github.com/bevyengine/bevy/pull/9002)
diff --git a/content/learn/migration-guides/0.12-to-0.13.md b/content/learn/migration-guides/0.12-to-0.13.md
index a581642a8f..498592e584 100644
--- a/content/learn/migration-guides/0.12-to-0.13.md
+++ b/content/learn/migration-guides/0.12-to-0.13.md
@@ -8,7 +8,7 @@ long_title = "Migration Guide: 0.12 to 0.13"
Bevy relies heavily on improvements in the Rust language and compiler.
As a result, the Minimum Supported Rust Version (MSRV) is "the latest stable release" of Rust.
-
+
### [Support all types of animation interpolation from gltf](https://github.com/bevyengine/bevy/pull/10755)
diff --git a/content/learn/migration-guides/0.9-to-0.10.md b/content/learn/migration-guides/0.9-to-0.10.md
index f496eca915..47c73f1cb3 100644
--- a/content/learn/migration-guides/0.9-to-0.10.md
+++ b/content/learn/migration-guides/0.9-to-0.10.md
@@ -9,7 +9,7 @@ weight = 5
Bevy relies heavily on improvements in the Rust language and compiler.
As a result, the Minimum Supported Rust Version (MSRV) is "the latest stable release" of Rust.
-
+
### [Migrate engine to Schedule v3 (stageless)](https://github.com/bevyengine/bevy/pull/7267)
diff --git a/generate-release/src/migration_guides.rs b/generate-release/src/migration_guides.rs
index a1771ac09a..13181dacd9 100644
--- a/generate-release/src/migration_guides.rs
+++ b/generate-release/src/migration_guides.rs
@@ -7,7 +7,7 @@ use crate::{
markdown::write_markdown_section,
};
use std::{
- collections::BTreeMap,
+ collections::{BTreeMap, BTreeSet},
fs::{self, OpenOptions},
io::Write as IoWrite,
path::PathBuf,
@@ -25,7 +25,7 @@ struct MigrationGuides {
struct MigrationGuide {
title: String,
prs: Vec,
- areas: Vec,
+ areas: BTreeSet,
file_name: String,
}
@@ -42,61 +42,48 @@ pub fn generate_migration_guides(
// Create the directory that will contain all the migration guides
std::fs::create_dir_all(&path).context(format!("Failed to create {path:?}"))?;
- // We'll write the file once at the end when all the metdaata is generated
- let mut guides_metadata = Vec::new();
-
- // If there is metadata that already exists,
- // and would contain info such as which PR already
- // has an entry, then get it and use it for that.
- let preexisting_metadata_file = fs::read_to_string(path.join("_guides.toml")).ok();
- // Deserializes the file inside the option into the `MigrationGuides` struct,
- // and then transposes / swaps the internal result of that operation to external,
- // and returns the error of that result if there is one,
- // else we have our preexisting metadata, ready to use.
- let preexisting_metadata: Option = preexisting_metadata_file
- .as_deref()
- .map(toml::from_str)
- .transpose()?;
-
- eprintln!("metadata exists? {}", preexisting_metadata.is_some());
-
- let mut new_prs = false;
+ let mut guides_metadata = if overwrite_existing {
+ vec![]
+ } else {
+ // If there is metadata that already exists,
+ // and would contain info such as which PR already
+ // has an entry, then get it and use it for that.
+ let preexisting_metadata_file = fs::read_to_string(path.join("_guides.toml")).ok();
+ // Deserializes the file inside the option into the `MigrationGuides` struct,
+ // and then transposes / swaps the internal result of that operation to external,
+ // and returns the error of that result if there is one,
+ // else we have our preexisting metadata, ready to use.
+ let preexisting_metadata: Option = preexisting_metadata_file
+ .as_deref()
+ .map(toml::from_str)
+ .transpose()?;
+
+ eprintln!("metadata exists? {}", preexisting_metadata.is_some());
+ // Populate the metadata to be written with the
+ // preexisting metadata so that it is not lost,
+ // or overwritten.
+ preexisting_metadata
+ .map(|metadata| metadata.guides)
+ .unwrap_or_default()
+ };
// Write all the separate migration guide files
for (area, prs) in areas {
- let mut prs = prs;
- // The PRs inside each area are sorted by close date
- // This doesn't really matter for the final output,
- // but it's useful to keep the metadata file in the same order between runs
- prs.sort_by_key(|k| k.1.closed_at);
-
for (title, pr) in prs {
// If a PR is already included in the migration guides,
// then do not generate anything for this PR.
- //
- // If overwrite_existing is true, then ignore
- // if the PRs may have already been generated.
- if preexisting_metadata.is_some() && !overwrite_existing {
- let preexisting_metadata = preexisting_metadata.clone().expect(
- "that preexisting metadata exists at the _guides.toml for this release version",
- );
- let mut pr_already_generated = false;
-
- for migration_guide in preexisting_metadata.guides {
- if migration_guide.prs.contains(&pr.number) {
- pr_already_generated = true;
- }
- }
+ let mut pr_already_generated = false;
- if pr_already_generated {
- eprintln!("PR #{} already exists", pr.number);
- continue;
+ for migration_guide in guides_metadata.iter() {
+ if migration_guide.prs.contains(&pr.number) {
+ pr_already_generated = true;
}
}
- // If the code has reached this point then that means
- // there is new PRs to be recorded.
- new_prs = true;
+ if pr_already_generated {
+ eprintln!("PR #{} already exists", pr.number);
+ continue;
+ }
// Slugify the title
let title_slug = title
@@ -112,45 +99,71 @@ pub fn generate_migration_guides(
// 64 is completely arbitrary but felt long enough and is a nice power of 2
file_name.truncate(64);
- // Generate the metadata block for this migration
- // We always re-generate it because we need to keep the ordering if a new migration is added
- let metadata_block = generate_metadata_block(&title, &file_name, &area, pr.number);
+ // Add the markdown extension
+ file_name = format!("{file_name}.md");
- let file_path = path.join(format!("{file_name}.md"));
+ let file_path = path.join(&file_name);
if write_migration_file(
&file_path,
pr.body.as_ref().context("PR has no body")?,
pr.number,
)? {
- guides_metadata.push(metadata_block);
+ guides_metadata.push(MigrationGuide {
+ title,
+ prs: vec![pr.number],
+ areas: area.clone().into_iter().collect(),
+ file_name,
+ });
}
}
}
- if !new_prs {
- return Ok(());
- }
+ // Sort by: Area in ascending order (empty areas at the end), and Title in ascending order
+ guides_metadata.sort_by(|a, b| {
+ let areas_cmp = match (a.areas.is_empty(), b.areas.is_empty()) {
+ (false, false) => {
+ let a_areas = a.areas.clone().into_iter().collect::>().join(" ");
+ let b_areas = b.areas.clone().into_iter().collect::>().join(" ");
+
+ a_areas.cmp(&b_areas)
+ }
+ (false, true) => std::cmp::Ordering::Less,
+ (true, false) => std::cmp::Ordering::Greater,
+ (true, true) => std::cmp::Ordering::Equal,
+ };
+
+ areas_cmp.then_with(|| a.title.cmp(&b.title))
+ });
+
+ // Create the metadata file, and overwrite it if it already exists.
+ //
+ // Note:
+ // The file, while overwritten,
+ // may still contain the same underlying data gotten from
+ // the preexisting metadata earlier, if overwrite_existing is false,
+ // thus preserving the data even if the file itself is overwritten.
+ let mut guides_toml = OpenOptions::new()
+ .write(true)
+ .truncate(true)
+ .create(true)
+ .open(path.join("_guides.toml"))
+ .context("Failed to create _guides.toml")?;
- let mut guides_toml = if overwrite_existing {
- // Replace and overwrite file.
- OpenOptions::new()
- .write(true)
- .truncate(true)
- .create(true)
- .open(path.join("_guides.toml"))
- .context("Failed to create _guides.toml")?
- } else {
- // Append to the metadata file,
- // creating it if necessary.
- OpenOptions::new()
- .append(true)
- .create(true)
- .open(path.join("_guides.toml"))
- .context("Failed to create _guides.toml")?
- };
for metadata in guides_metadata {
- writeln!(&mut guides_toml, "{metadata}")?;
+ // Generate the metadata block for this migration.
+ //
+ // We always freshly generate and write this data to the file,
+ // rather than appending to the end-of-file,
+ // so that we can maintain proper ordering of the entries.
+ let metadata_block = generate_metadata_block(
+ &metadata.title,
+ &metadata.file_name,
+ &metadata.areas.into_iter().collect::>(),
+ &metadata.prs,
+ );
+
+ writeln!(&mut guides_toml, "{metadata_block}")?;
}
Ok(())
@@ -201,15 +214,20 @@ fn generate_metadata_block(
title: &str,
file_name: &String,
areas: &[String],
- pr_number: u64,
+ pr_number: &[u64],
) -> String {
format!(
r#"[[guides]]
title = "{title}"
-prs = [{pr_number}]
+prs = [{pr_numbers}]
areas = [{areas}]
-file_name = "{file_name}.md"
+file_name = "{file_name}"
"#,
+ pr_numbers = pr_number
+ .iter()
+ .map(|pr| pr.to_string())
+ .collect::>()
+ .join(", "),
areas = areas
.iter()
.map(|area| format!("\"{area}\""))
diff --git a/release-content/0.14/migration-guides/_guides.toml b/release-content/0.14/migration-guides/_guides.toml
index b95734f8f4..764edbaccc 100644
--- a/release-content/0.14/migration-guides/_guides.toml
+++ b/release-content/0.14/migration-guides/_guides.toml
@@ -1,45 +1,3 @@
-[[guides]]
-title = "Overhaul `Color`"
-prs = ["12163"]
-areas = ["Color", "Gizmos", "Rendering", "Text", "UI"]
-file_name = "12163_Migrate_from_LegacyColor_to_bevy_colorColor.md"
-
-[[guides]]
-title = "Make default behavior for `BackgroundColor` and `BorderColor` more intuitive"
-prs = ["14017"]
-areas = ["Rendering", "UI"]
-file_name = "14017_Make_default_behavior_for_BackgroundColor_and_BorderColor_.md"
-
-[[guides]]
-title = "Register missing types manually"
-prs = ["12314"]
-areas = ["Reflection"]
-file_name = "12314_Clean_up_type_registrations.md"
-
-[[guides]]
-title = "`OnEnter` state schedules now run before Startup schedules"
-prs = ["11426"]
-areas = ["App", "ECS"]
-file_name = "11426_on_enter_startup_states.md"
-
-[[guides]]
-title = "Fix `Node2d` typo"
-prs = ["12038"]
-areas = []
-file_name = "12038_fix_some_typos.md"
-
-[[guides]]
-title = "Update to `fixedbitset` 0.5"
-prs = ["12512"]
-areas = []
-file_name = "12512_Update_to_fixedbitset_05.md"
-
-[[guides]]
-title = "Move WASM panic handler from `LogPlugin` to `PanicHandlerPlugin`"
-prs = ["12557"]
-areas = []
-file_name = "12557_refactor_separate_out_PanicHandlerPlugin.md"
-
[[guides]]
title = "`AnimationClip` now uses UUIDs and `NoOpTypeIdHash` is now `NoOpHash`"
prs = ["11707"]
@@ -58,6 +16,12 @@ prs = ["12575"]
areas = ["Animation", "Color", "Math", "Rendering"]
file_name = "12575_Color_maths_4.md"
+[[guides]]
+title = "`OnEnter` state schedules now run before Startup schedules"
+prs = ["11426"]
+areas = ["App", "ECS"]
+file_name = "11426_on_enter_startup_states.md"
+
[[guides]]
title = "Separate `SubApp` from `App`"
prs = ["9202"]
@@ -148,6 +112,12 @@ prs = ["12407"]
areas = ["Audio"]
file_name = "12407_Fix_leftover_references_to_children_when_despawning_audio_.md"
+[[guides]]
+title = "Overhaul `Color`"
+prs = ["12163"]
+areas = ["Color", "Gizmos", "Rendering", "Text", "UI"]
+file_name = "12163_Migrate_from_LegacyColor_to_bevy_colorColor.md"
+
[[guides]]
title = "Move WGSL math constants and color operations from `bevy_pbr` to `bevy_render`"
prs = ["13209"]
@@ -340,6 +310,12 @@ prs = ["13261"]
areas = ["Gizmos"]
file_name = "13261_More_gizmos_builders.md"
+[[guides]]
+title = "Contextually clearing gizmos"
+prs = ["10973"]
+areas = ["Gizmos"]
+file_name = "10973_Contextually_clearing_gizmos.md"
+
[[guides]]
title = "Rename touchpad input to gesture"
prs = ["13660"]
@@ -358,6 +334,12 @@ prs = ["13678"]
areas = ["Input", "Windowing"]
file_name = "13678_flush_key_input_cache_when_Bevy_loses_focus_Adopted.md"
+[[guides]]
+title = "Separating Finite and Infinite 3d Planes"
+prs = ["12426"]
+areas = ["Math", "Rendering"]
+file_name = "12426_separating_finite_and_infinite_3d_planes.md"
+
[[guides]]
title = "Move direction types out of `bevy::math::primitives`"
prs = ["12018"]
@@ -442,6 +424,12 @@ prs = ["12732"]
areas = ["Math", "Utils"]
file_name = "12732_Move_FloatOrd_into_bevy_math.md"
+[[guides]]
+title = "Register missing types manually"
+prs = ["12314"]
+areas = ["Reflection"]
+file_name = "12314_Clean_up_type_registrations.md"
+
[[guides]]
title = "Change `ReflectSerialize` trait bounds"
prs = ["12024"]
@@ -472,6 +460,12 @@ prs = ["12715"]
areas = ["Reflection", "Scenes"]
file_name = "12715_Fix_TypeRegistry_use_in_dynamic_scene.md"
+[[guides]]
+title = "Make default behavior for `BackgroundColor` and `BorderColor` more intuitive"
+prs = ["14017"]
+areas = ["Rendering", "UI"]
+file_name = "14017_Make_default_behavior_for_BackgroundColor_and_BorderColor_.md"
+
[[guides]]
title = "Rename `Camera3dBundle::dither` to `deband_dither`"
prs = ["11939"]
@@ -767,13 +761,19 @@ areas = ["Windowing"]
file_name = "13366_fix_upgrade_to_winit_v030.md"
[[guides]]
-title = "Separating Finite and Infinite 3d Planes"
-prs = ["12426"]
-areas = ["Math", "Rendering"]
-file_name = "12426_separating_finite_and_infinite_3d_planes.md"
+title = "Fix `Node2d` typo"
+prs = ["12038"]
+areas = []
+file_name = "12038_fix_some_typos.md"
[[guides]]
-title = "Contextually clearing gizmos"
-prs = ["10973"]
-areas = ["Gizmos"]
-file_name = "10973_Contextually_clearing_gizmos.md"
+title = "Update to `fixedbitset` 0.5"
+prs = ["12512"]
+areas = []
+file_name = "12512_Update_to_fixedbitset_05.md"
+
+[[guides]]
+title = "Move WASM panic handler from `LogPlugin` to `PanicHandlerPlugin`"
+prs = ["12557"]
+areas = []
+file_name = "12557_refactor_separate_out_PanicHandlerPlugin.md"
diff --git a/sass/pages/_content.scss b/sass/pages/_content.scss
index d49b8044be..4c13e61a4e 100644
--- a/sass/pages/_content.scss
+++ b/sass/pages/_content.scss
@@ -5,7 +5,7 @@ $content-font-size: 1.22rem;
font-size: $content-font-size;
font-weight: 400;
line-height: 1.43;
- color: #d2d2d2;
+ color: #bbb;
font-style: normal;
text-decoration: none;
word-break: break-word;
diff --git a/sass/pages/_migration_guide.scss b/sass/pages/_migration_guide.scss
index 1aef0c362c..a42cef3f13 100644
--- a/sass/pages/_migration_guide.scss
+++ b/sass/pages/_migration_guide.scss
@@ -1,4 +1,53 @@
.migration-guide {
+ h1, h2, h3 {
+ color: #eee;
+ }
+
+ h2 {
+ margin-block: 5rem 1rem;
+
+ &:first-child {
+ margin-top: 3rem;
+ }
+ }
+
+ h2 + h3 {
+ margin-top: 0;
+ padding-top: 0;
+ border-top: 0;
+ text-wrap: pretty;
+ }
+
+ h3 {
+ margin-block: 2rem .5rem;
+ padding-top: 2rem;
+ border-top: solid rgba(#fff, 0.05) 1px;
+ }
+}
+
+.migration-guide-meta {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ list-style: none;
+ padding: 0px !important;
+ margin: 0px 0px 1rem !important;
+
+ li {
+ font-size: 0.9rem;
+ }
+
+ &__area {
+ padding: 0.2rem 0.3rem;
+ line-height: 1;
+ border-radius: 0.2rem;
+ border-style: solid;
+ border-width: 1px;
+ color: #888;
+ }
+}
+
+.migration-guide-legacy {
h3 {
margin-top: 2rem;
padding-top: 2rem;
@@ -6,6 +55,33 @@
border-top: solid darken($color-white, 60%) 1px;
}
+ .migration-guide-area-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.2rem;
+ color: gray;
+ }
+
+ .migration-guide-area-tag {
+ display: block;
+ font-size: 0.8rem;
+ padding-left: 0.2rem;
+ padding-right: 0.2rem;
+ padding-top: 0.2rem;
+ padding-bottom: 0.2rem;
+ margin-top: 0.3rem;
+ margin-bottom: 0.3rem;
+ line-height: 1;
+ border-radius: 0.3rem;
+ border-style: solid;
+ border-width: 1px;
+ }
+
+ ul.migration-guide-pr-list {
+ list-style: none;
+ padding: 0px;
+ }
+
p,
ul,
li,
@@ -13,31 +89,3 @@
font-size: 1rem;
}
}
-
-.migration-guide-area-tags {
- display: flex;
- flex-wrap: wrap;
- gap: 0.2rem;
- color: gray;
-}
-
-.migration-guide-area-tag {
- display: block;
- font-size: 0.8rem;
- padding-left: 0.2rem;
- padding-right: 0.2rem;
- padding-top: 0.2rem;
- padding-bottom: 0.2rem;
- margin-top: 0.3rem;
- margin-bottom: 0.3rem;
- line-height: 1;
- border-radius: 0.3rem;
- border-style: solid;
- border-width: 1px;
-}
-
-ul.migration-guide-pr-list {
- list-style: none;
- padding: 0px;
-}
-
diff --git a/templates/shortcodes/migration_guides.md b/templates/shortcodes/migration_guides.md
index adf1d12fd1..a26d6659aa 100644
--- a/templates/shortcodes/migration_guides.md
+++ b/templates/shortcodes/migration_guides.md
@@ -2,6 +2,7 @@
{% set base_path = macros::release_path(version=version, path="/migration-guides/") %}
{% set guides_data = load_data(path=macros::path_join(path_a=base_path, path_b="/_guides.toml")) %}
+{% set previous_area = "" %}