Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh

Commit

The g1t CLI prints JSON with each object's keys in sorted order however it is built, and its table of API operations lists each body's fields in sorted order. Another crate in the workspace turns on serde_json's preserve_order, and a shared build carried it into the CLI, so --json output and the generated table changed order depending on what was built alongside it, and cargo test across the workspace failed. The table is regenerated for the API after open sign-ups, which no longer has the personal invite operations.

syntaqxcommitted Parent6155a80Browse files
4 files+22−380/4 viewed
+1−1
6969 pub fn line(value: &Value) -> String {
7070 match value {
7171 Value::String(s) => s.clone(),
72− other => serde_json::to_string(other).expect("json"),
72+ other => serde_json::to_string(&crate::output::sorted(other)).expect("json"),
7373 }
7474 }
7575
+4−0
184184 match schema["properties"].as_object() {
185185 Some(props) if !props.is_empty() => {
186186 writeln!(text, " body: &[").unwrap();
187+ // Sorted, so the table is the same with or without
188+ // serde_json's preserve_order in the build.
189+ let mut props: Vec<(&String, &Value)> = props.iter().collect();
190+ props.sort_by_key(|(name, _)| *name);
187191 for (name, field) in props {
188192 writeln!(
189193 text,
+0−36
20292029 body: &[],
20302030 },
20312031 Operation {
2032− id: "create_invite",
2033− method: "POST",
2034− path: "/user/invites",
2035− tag: "Invites",
2036− summary: "Create an invite",
2037− scope: Some("account:write"),
2038− params: &[],
2039− body: &[
2040− Field { name: "charge_workspace", kind: "string", required: false, values: &[] },
2041− Field { name: "email", kind: "string", required: false, values: &[] },
2042− Field { name: "workspace", kind: "string", required: false, values: &[] },
2043− ],
2044− },
2045− Operation {
20462032 id: "decline_invitation",
20472033 method: "POST",
20482034 path: "/user/invitations/{id}/decline",
20762062 path: "/user/invitations",
20772063 tag: "Invites",
20782064 summary: "List your workspace invitations",
2079− scope: Some("account:read"),
2080− params: &[],
2081− body: &[],
2082− },
2083− Operation {
2084− id: "list_invites",
2085− method: "GET",
2086− path: "/user/invites",
2087− tag: "Invites",
2088− summary: "List your invites",
20892065 scope: Some("account:read"),
20902066 params: &[],
20912067 body: &[],
20992075 scope: Some("workspace:read"),
21002076 params: &[
21012077 Param { name: "workspace", location: In::Path, kind: "string", required: true, values: &[] },
2102− ],
2103− body: &[],
2104− },
2105− Operation {
2106− id: "revoke_invite",
2107− method: "DELETE",
2108− path: "/user/invites/{id}",
2109− tag: "Invites",
2110− summary: "Revoke an invite",
2111− scope: Some("account:write"),
2112− params: &[
2113− Param { name: "id", location: In::Path, kind: "string", required: true, values: &[] },
21142078 ],
21152079 body: &[],
21162080 },
+17−1
6666 }
6767 return Ok(());
6868 }
69+ let value = sorted(&value);
6970 let text = if self.tty {
7071 serde_json::to_string_pretty(&value)
7172 } else {
203204 }
204205 }
205206
207+/// `value` with every object's keys in sorted order. Printed JSON must not
208+/// depend on serde_json's `preserve_order`, which other crates in the
209+/// workspace turn on for a shared build.
210+pub fn sorted(value: &Value) -> Value {
211+ match value {
212+ Value::Object(map) => {
213+ let mut keys: Vec<&String> = map.keys().collect();
214+ keys.sort();
215+ Value::Object(keys.into_iter().map(|k| (k.clone(), sorted(&map[k]))).collect())
216+ }
217+ Value::Array(list) => Value::Array(list.iter().map(sorted).collect()),
218+ other => other.clone(),
219+ }
220+}
221+
206222 /// Keeps only `fields` of each object in `value`.
207223 pub fn select(value: &Value, fields: &[String]) -> Result<Value> {
208224 let objects: Vec<&Map<String, Value>> = match value {
365381 fn json_is_compact_and_ordered() {
366382 let value: Value = serde_json::from_str(r#"{"title":"a","number":1}"#).unwrap();
367383 assert_eq!(
368− serde_json::to_string(&value).unwrap(),
384+ serde_json::to_string(&sorted(&value)).unwrap(),
369385 r#"{"number":1,"title":"a"}"#
370386 );
371387 }

Comments

Sign in to comment.