{"record":{"id":"383d44d98bf39dcd","repo":"gitbutlerapp/gitbutler","slug":"reactions-for-forge-forge-are-not-implemented","errorCode":null,"errorMessage":"Reactions for forge {forge:?} are not implemented yet.","messagePattern":"Reactions for forge (.+?) are not implemented yet\\.","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-forge/src/review.rs","lineNumber":1554,"sourceCode":") -> Result<ForgeReviewReaction> {\n    let crate::forge::ForgeRepoInfo {\n        forge, owner, repo, ..\n    } = forge_repo_info;\n    match forge {\n        ForgeName::GitHub => {\n            let preferred_account = preferred_forge_user.as_ref().and_then(|user| user.github());\n            let reaction = but_github::pr::add_review_reaction(\n                preferred_account,\n                owner,\n                repo,\n                review_number,\n                kind,\n                storage,\n            )\n            .await?;\n            Ok(github_reaction(reaction))\n        }\n        _ => Err(anyhow::anyhow!(\n            \"Reactions for forge {forge:?} are not implemented yet.\"\n        )),\n    }\n}\n\n/// Remove one of the caller's reactions from the review itself.\npub async fn remove_review_reaction(\n    preferred_forge_user: &Option<crate::ForgeUser>,\n    forge_repo_info: &crate::forge::ForgeRepoInfo,\n    review_number: usize,\n    reaction_id: i64,\n    storage: &but_forge_storage::Controller,\n) -> Result<()> {\n    let crate::forge::ForgeRepoInfo {\n        forge, owner, repo, ..\n    } = forge_repo_info;\n    match forge {\n        ForgeName::GitHub => {","sourceCodeStart":1536,"sourceCodeEnd":1572,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-forge/src/review.rs#L1536-L1572","documentation":"`add_review_reaction()` adds the caller's reaction (e.g. an emoji) to the review itself. Only GitHub is implemented (via `but_github::pr::add_review_reaction`, mapped through `github_reaction`); GitLab, Bitbucket and Azure hit the wildcard arm and fail before any network call.","triggerScenarios":"Reacting to a PR/MR whose `ForgeRepoInfo.forge` is GitLab, Bitbucket or Azure — e.g. the emoji button on the review header of a non-GitHub review.","commonSituations":"Reaction UIs enabled for every forge; GitHub-parity assumptions in shared components; SDK integrations that toggle reactions programmatically.","solutions":["Use the forge's native reactions API/UI for non-GitHub reviews.","Hide reaction buttons for non-GitHub reviews.","Implement reaction backends in `but_gitlab`/`but_bitbucket` and extend the match at crates/but-forge/src/review.rs:1546-1554."],"exampleFix":"// before\nadd_review_reaction(&user, &info, number, \"heart\", &storage).await?;\n\n// after\nif !matches!(info.forge, ForgeName::GitHub) {\n    return Ok(Default::default()); // reactions are GitHub-only; hide the button\n}\nadd_review_reaction(&user, &info, number, \"heart\", &storage).await?;","handlingStrategy":"validation","validationCode":"use but_forge::forge::ForgeName;\n\nif !matches!(info.forge, ForgeName::GitHub) {\n    // hide reaction buttons on the review header\n}","typeGuard":"fn review_reactions_supported(forge: &but_forge::forge::ForgeName) -> bool {\n    matches!(forge, ForgeName::GitHub)\n}","tryCatchPattern":"match add_review_reaction(&user, &info, number, kind, &storage).await {\n    Ok(r) => r,\n    Err(e) if e.to_string().contains(\"not implemented yet\") => { /* don't toggle emoji state */ return Ok(Default::default()); }\n    Err(e) => return Err(e),\n}","preventionTips":["Gate all four reaction operations (add/remove x review/comment) behind one forge capability check.","Don't optimistically render the reaction before the forge confirms.","Use one 'reactions supported' flag rather than per-button checks to avoid drift."],"tags":["rust","but-forge","reactions","github","not-implemented"],"backgroundTag":"not-implemented-for-platform","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}