Skip to content

Conversation

@ReneWerner87
Copy link
Member

@ReneWerner87 ReneWerner87 commented Nov 27, 2025

When using extends, by default, the code is not merged but overwritten.

The Probot documentation recommends using deepmerge.

https://github.com/probot/octokit-plugin-config/#merging-configuration

@gemini-code-assist
Copy link

Summary of Changes

Hello @ReneWerner87, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces the deepmerge utility to the project, enhancing the capability to merge configuration objects. This change specifically improves how default configurations are handled and applied by leveraging deepmerge's recursive merging functionality within the configuration loading process.

Highlights

  • Dependency Addition: The deepmerge library (version ^4.3.1) has been added as a new dependency to the project, as reflected in package.json and package-lock.json.
  • Configuration Merging: The src/config.ts file now utilizes the deepmerge.all function within the composeConfigGet call to provide a robust mechanism for merging multiple configuration objects, ensuring proper handling of defaults.
  • License Update: The dist/licenses.txt file has been updated to include the MIT license for the newly added deepmerge package.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@ReneWerner87 ReneWerner87 merged commit 870f0d2 into main Nov 27, 2025
10 of 11 checks passed
@ReneWerner87 ReneWerner87 deleted the deepMerge branch November 27, 2025 17:58
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the deepmerge dependency to merge configuration files from multiple sources. The implementation is generally correct, but I've identified a couple of areas for improvement in src/config.ts to enhance robustness and type safety. Specifically, I'm suggesting replacing a fragile import from a dependency's internal directory with a local type definition and improving the deepmerge usage to be more type-safe by explicitly handling potential null values.

import reporter from 'io-ts-reporters';
import { isRight } from 'fp-ts/Either';
import { composeConfigGet } from '@probot/octokit-plugin-config';
import { Configuration } from '@probot/octokit-plugin-config/dist-types/types';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Importing types from a dist-types directory is fragile as it relies on the internal implementation details of a dependency. This can break your build on minor or patch updates of @probot/octokit-plugin-config. It's safer to define this type locally, as it's a simple type.

Suggested change
import { Configuration } from '@probot/octokit-plugin-config/dist-types/types';
type Configuration = Record<string, any> | null;

repo,
path: configPath,
branch: repoName === github.context.payload.repository?.full_name ? github.context.sha : undefined,
defaults: (configs: Configuration[]): Configuration => all<Configuration>([...configs]),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The use of all<Configuration> is not ideal because the Configuration type alias includes null. While deepmerge appears to handle null values by ignoring them, it's safer and more explicit to filter them out. This improves type safety and allows TypeScript to correctly infer the types for all, removing the need for an explicit generic. The spread operator [...configs] is also redundant as deepmerge does not mutate its input array.

Suggested change
defaults: (configs: Configuration[]): Configuration => all<Configuration>([...configs]),
defaults: (configs: Configuration[]): Configuration => all(configs.filter((c): c is Record<string, any> => c !== null)),

@coderabbitai
Copy link

coderabbitai bot commented Nov 27, 2025

Walkthrough

Added imports for Configuration type and deepmerge utility. Extended the getConfig function to merge multiple default Configuration objects using deepmerge's all function, enabling layered default configuration composition.

Changes

Cohort / File(s) Summary
Configuration merging enhancement
src/config.ts
Added imports for Configuration type and deepmerge utility. Extended getConfig to compose default configurations by merging an array of Configuration objects using deepmerge's all function.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

  • Verify that deepmerge's all function handles the Configuration object structure as expected
  • Confirm the order of configuration merging produces the intended precedence

Poem

🐰 A rabbit hops through configs deep,
Merging defaults in a heap,
Deepmerge weaves them all as one,
Configuration layering—how fun! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: adding the deepmerge dependency and integrating it into the config merging logic.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch deepMerge

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/config.ts (1)

6-6: Use a type‑only import for Configuration.

Configuration is only used for typing the defaults callback, so this can be a type import, avoiding a runtime dependency on the internal dist-types path and matching the pattern already used for ProbotOctokit:

-import { Configuration } from '@probot/octokit-plugin-config/dist-types/types';
+import type { Configuration } from '@probot/octokit-plugin-config/dist-types/types';
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca1b391 and dddb6a8.

⛔ Files ignored due to path filters (5)
  • dist/index.js is excluded by !**/dist/**, !dist/**
  • dist/index.js.map is excluded by !**/dist/**, !**/*.map, !dist/**, !**/*.map
  • dist/licenses.txt is excluded by !**/dist/**, !dist/**
  • package-lock.json is excluded by !**/package-lock.json, !**/*.json
  • package.json is excluded by !**/*.json
📒 Files selected for processing (1)
  • src/config.ts (2 hunks)

import type { Octokit as ProbotOctokit } from '@octokit/core';
import { GitHub } from '@actions/github/lib/utils';
import * as github from '@actions/github';
import { all } from 'deepmerge';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# 1. Check package.json for deepmerge version
echo "=== Checking deepmerge version in package.json ==="
if [ -f package.json ]; then
  cat package.json | grep -A2 -B2 deepmerge || echo "deepmerge not found in package.json"
fi

# 2. Read src/config.ts to see current state
echo -e "\n=== Current state of src/config.ts ==="
if [ -f src/config.ts ]; then
  wc -l src/config.ts
  echo "--- Lines 1-20 (imports section) ---"
  head -20 src/config.ts
  echo "--- Lines 100-115 (around line 106) ---"
  sed -n '100,115p' src/config.ts
fi

Repository: gofiber/multi-labeler

Length of output: 186


🌐 Web query:

deepmerge 4.3.1 export structure named export all

💡 Result:

deepmerge v4.3.1 is exported as a CommonJS function (require('deepmerge')), not as ES named exports. The package's main export is the merge function and it exposes merge.all as a property (i.e. merge.all(...)). [1][2]

Sources:

  • npm package README (shows require('deepmerge') and merge.all API). [1]
  • index.d.ts / type declarations (export = deepmerge; deepmerge.all signature). [2]

🌐 Web query:

deepmerge package type definitions index.d.ts default export

💡 Result:

The deepmerge type file declares a CommonJS-style export (a callable function + namespace) and ends with "export = deepmerge", i.e. not an ES default export. Use one of these in TypeScript:

  • import deepmerge = require('deepmerge'); // works without interop
  • OR enable esModuleInterop / allowSyntheticDefaultImports and use:
    import deepmerge from 'deepmerge';

Evidence (index.d.ts shows the signature + "export = deepmerge"). [1] The @types package is deprecated because deepmerge ships its own types. [2]

Sources:
[1] deepmerge index.d.ts (shows declarations and "export = deepmerge").
[2] @types/deepmerge npm page (deprecated; note deepmerge provides its own types).


🌐 Web query:

@probot/octokit-plugin-config deepmerge.all usage

💡 Result:

Use deepmerge.all to combine your default config with loaded configs inside the plugin's defaults function. Example:

import deepmerge from 'deepmerge'
const defaults = { settings: { one: 'default', two: 'default' } }
const { config } = await octokit.config.get({
  owner,
  repo,
  path: '.github/my-app.yml',
  defaults: (configs) => deepmerge.all([defaults, ...configs])
})

This is the pattern shown in the @probot/octokit-plugin-config README; deepmerge.all merges an array of objects deeply. [1][2]

Sources:

  • @probot/octokit-plugin-config README (usage showing deepmerge.all). [1]
  • deepmerge npm docs (merge.all / deepmerge.all API). [2]

🌐 Web query:

deepmerge.all empty array behavior runtime error

💡 Result:

deepmerge.all throws if you pass an empty array (or an array with fewer than two elements). The implementation validates the input and raises: "first argument should be an array with at least two elements". See the function source/docs. [1][2]

Workarounds

  • Ensure you only call merge.all when you have >= 2 objects.
  • Or provide a safe initial object, e.g. merge.all([{}, ...objects]) so merge.all always receives at least two items.
  • Or guard in code: objects.length === 0 ? {} : objects.length === 1 ? objects[0] : merge.all(objects).

Sources

  1. deepmerge source/docs (all / README). [GitHub / deepmerge]. [2]
  2. API/source excerpt showing the input check and thrown error (npmdoc). [3]

Based on my verification through web search, I can now confirm the key claims in the original review comment:

Verified findings:

  1. Named import issue is real: deepmerge 4.3.1 uses CommonJS export (export = deepmerge), NOT ES named exports. The named import { all } does not exist in the type definitions and will cause a type-checking/bundling failure.
  2. Empty array guard is necessary: deepmerge.all([]) throws the error "first argument should be an array with at least two elements", so the guard is a valid runtime safety measure.
  3. Correct import pattern: The suggested fix import deepmerge from 'deepmerge' matches the official @probot/octokit-plugin-config documentation and works with TypeScript's esModuleInterop.

The original review comment is accurate and the suggested fix is correct. This is a critical issue that will break the build.


Final Rewritten Review Comment

Fix named import syntax for deepmerge—will fail type-checking and cause build to break.

deepmerge 4.3.1 does not export all as a named export. The package uses CommonJS style (export = deepmerge), meaning all is a property on the default export. The statement import { all } from 'deepmerge' will fail type-checking. Additionally, deepmerge.all([]) throws when given fewer than two elements, so if configs can be empty, a runtime error will occur.

-import { all } from 'deepmerge';
+import deepmerge from 'deepmerge';
@@
-    defaults: (configs: Configuration[]): Configuration => all<Configuration>([...configs]),
+    defaults: (configs: Configuration[]): Configuration =>
+      configs.length ? deepmerge.all<Configuration>(configs) : ({} as Configuration),

Adjust the fallback {} to whatever default shape makes sense for your configuration, or keep deepmerge.all(configs) if you're certain configs is never empty.

Also applies to: 106-107

🤖 Prompt for AI Agents
In src/config.ts around line 10 (and also apply same fix to lines 106-107),
replace the invalid named import "import { all } from 'deepmerge'" with a
default import "import deepmerge from 'deepmerge'" and update usages to call
deepmerge.all(...); additionally, guard against calling deepmerge.all on an
empty array by returning an appropriate default config (e.g., {}) when
configs.length === 0 (or ensure configs always has at least two entries) so
runtime errors are avoided.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants