From 3d12840e98a0909f450e6217adafe04ff62cebfa Mon Sep 17 00:00:00 2001 From: Allen Houchins <32207388+allenhouchins@users.noreply.github.com> Date: Tue, 9 Dec 2025 13:44:11 -0600 Subject: [PATCH] Add Bruno as a macOS FMA (#36998) This pull request adds support for the Bruno application to both the backend maintained apps system and the frontend software page. The main changes introduce Bruno's metadata, installation and uninstallation scripts, and its icon for display in the UI. **Backend: Bruno app integration** * Added `bruno.json` input definition for Bruno, specifying its installer format, unique identifier, and default categories. * Updated `apps.json` output to include Bruno with its description, platform, and slug. * Created output file `bruno/darwin.json` with Bruno's version info, installer and uninstall script references, SHA256 checksum, and category. **Frontend: Bruno icon and mapping** * Added `Bruno.tsx` SVG icon component for Bruno. * Imported Bruno icon in the icons index and mapped it in `SOFTWARE_NAME_TO_ICON_MAP` for use on the software page. [[1]](diffhunk://#diff-628095892e1d16090be1db6cc1a5c9cebc65248c32a8b1312385394818f2907bR25) [[2]](diffhunk://#diff-628095892e1d16090be1db6cc1a5c9cebc65248c32a8b1312385394818f2907bR183) --- ee/maintained-apps/inputs/homebrew/bruno.json | 8 +++++++ ee/maintained-apps/outputs/apps.json | 7 ++++++ ee/maintained-apps/outputs/bruno/darwin.json | 21 ++++++++++++++++++ .../SoftwarePage/components/icons/Bruno.tsx | 14 ++++++++++++ .../SoftwarePage/components/icons/index.ts | 2 ++ .../assets/images/app-icon-bruno-60x60@2x.png | Bin 0 -> 13754 bytes 6 files changed, 52 insertions(+) create mode 100644 ee/maintained-apps/inputs/homebrew/bruno.json create mode 100644 ee/maintained-apps/outputs/bruno/darwin.json create mode 100644 frontend/pages/SoftwarePage/components/icons/Bruno.tsx create mode 100644 website/assets/images/app-icon-bruno-60x60@2x.png diff --git a/ee/maintained-apps/inputs/homebrew/bruno.json b/ee/maintained-apps/inputs/homebrew/bruno.json new file mode 100644 index 0000000000..2a45825ffd --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/bruno.json @@ -0,0 +1,8 @@ +{ + "name": "Bruno", + "unique_identifier": "com.usebruno.app", + "token": "bruno", + "installer_format": "dmg", + "slug": "bruno/darwin", + "default_categories": ["Developer tools"] +} diff --git a/ee/maintained-apps/outputs/apps.json b/ee/maintained-apps/outputs/apps.json index 70e38c2647..14616beccc 100644 --- a/ee/maintained-apps/outputs/apps.json +++ b/ee/maintained-apps/outputs/apps.json @@ -169,6 +169,13 @@ "unique_identifier": "Brave", "description": "Brave is a web browser designed with privacy, blocking ads and trackers by default while maintaining fast speed." }, + { + "name": "Bruno", + "slug": "bruno/darwin", + "platform": "darwin", + "unique_identifier": "com.usebruno.app", + "description": "Bruno is an open source IDE for exploring and testing APIs." + }, { "name": "Camtasia", "slug": "camtasia/darwin", diff --git a/ee/maintained-apps/outputs/bruno/darwin.json b/ee/maintained-apps/outputs/bruno/darwin.json new file mode 100644 index 0000000000..7875ac752f --- /dev/null +++ b/ee/maintained-apps/outputs/bruno/darwin.json @@ -0,0 +1,21 @@ +{ + "versions": [ + { + "version": "2.15.1", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.usebruno.app';" + }, + "installer_url": "https://github.com/usebruno/bruno/releases/download/v2.15.1/bruno_2.15.1_arm64_mac.dmg", + "install_script_ref": "4fa6591d", + "uninstall_script_ref": "28a81327", + "sha256": "691813ebc0ac244826f995b530fbd43766ccc7c288a4acdac46baee859055816", + "default_categories": [ + "Developer tools" + ] + } + ], + "refs": { + "28a81327": "#!/bin/sh\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Bruno.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/bruno'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.usebruno.app.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.usebruno.app.savedState'\n", + "4fa6591d": "#!/bin/sh\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath $INSTALLER_PATH)\")\n# functions\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n if ! osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ $EUID -eq 0 && \"$console_user\" == \"root\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nhdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\"\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\"\n# copy to the applications folder\nquit_application 'com.usebruno.app'\nif [ -d \"$APPDIR/Bruno.app\" ]; then\n\tsudo mv \"$APPDIR/Bruno.app\" \"$TMPDIR/Bruno.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Bruno.app\" \"$APPDIR\"\n" + } +} diff --git a/frontend/pages/SoftwarePage/components/icons/Bruno.tsx b/frontend/pages/SoftwarePage/components/icons/Bruno.tsx new file mode 100644 index 0000000000..845e33788c --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Bruno.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Bruno = (props: SVGProps) => ( + + + +); +export default Bruno; diff --git a/frontend/pages/SoftwarePage/components/icons/index.ts b/frontend/pages/SoftwarePage/components/icons/index.ts index 82bddcaf1f..2bceee116e 100644 --- a/frontend/pages/SoftwarePage/components/icons/index.ts +++ b/frontend/pages/SoftwarePage/components/icons/index.ts @@ -23,6 +23,7 @@ import Bitwarden from "./Bitwarden"; import Blender from "./Blender"; import Box from "./Box"; import Brave from "./Brave"; +import Bruno from "./Bruno"; import CLion from "./CLion"; import Camtasia from "./Camtasia"; import Canva from "./Canva"; @@ -181,6 +182,7 @@ export const SOFTWARE_NAME_TO_ICON_MAP = { blender: Blender, box: Box, brave: Brave, + bruno: Bruno, camtasia: Camtasia, canva: Canva, "chatgpt atlas": ChatGptAtlas, diff --git a/website/assets/images/app-icon-bruno-60x60@2x.png b/website/assets/images/app-icon-bruno-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..04bcf95cec2ad3ad61640e3200178aeb1a2f77a2 GIT binary patch literal 13754 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 z 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 OoWzA?gsKGe0{$2H=K<^h literal 0 HcmV?d00001