Skip to content

Conversation

devtedlee
Copy link

@devtedlee devtedlee commented Aug 3, 2025

Summary

This pull request introduces a configuration file system for the Fedify CLI, allowing users to set persistent options in .fedifyrc or fedify.config.json. It also centralizes and refactors command-line option handling to improve structural clarity, maintainability, and user experience by establishing a clear priority for settings.

Related Issue

Changes

  • Created packages/cli/src/config.ts with an interface for configuration and a loadConfig function to read .fedifyrc and fedify.config.json files.
  • Added unit tests for the configuration loading logic.
  • Implemented a central globalAction in mod.ts to manage shared options and resource initialization (e.g., cache directory).
  • Established a clear option precedence: Command-line flags > Config file settings > Hardcoded defaults.
  • Introduced a --no-config flag to allow bypassing the configuration file loading.
  • Relocated several global options (e.g., --user-agent) to their relevant subcommands (lookup, nodeinfo, webfinger).
  • Centralized log level management based on --debug and --verbose flags within the globalAction.

Benefits

  • Improved Configurability: Users can define project-level settings in a configuration file, avoiding repetitive command-line flags and making the CLI easier to use.
  • Enhanced Clarity: Moving options to specific subcommands makes the CLI's interface more intuitive and self-documenting.
  • Increased Maintainability: Centralizing the logic for option parsing and merging into a single globalAction reduces code duplication and simplifies future development.
  • Greater Flexibility & Testability: The --no-config flag enables running the CLI in an isolated state, which is crucial for scripting, automation, and reliable testing.
  • Consistent Behavior: Shared resources and logging are initialized consistently across all commands, leading to more predictable outcomes.

Checklist

  • Did you add a changelog entry to the CHANGES.md?
  • Did you write some relevant docs about this change (if it's a new feature)?
  • Did you write a regression test to reproduce the bug (if it's a bug fix)?
  • Did you write some tests for this change (if it's a new feature)?
  • Did you run deno task test-all on your machine?

Additional Notes

This work was done incrementally, starting with adding the core config loading feature and then refactoring the option parsing logic for better structure. The changes affect the core CLI module and several subcommands, establishing a new, more robust foundation for how the CLI is configured.

Focus on Review

  • find out configs to apply: timeout, followRedirects, format

Copy link
Contributor

@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.

Summary of Changes

Hello @devtedlee, 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!

I've implemented a new configuration system for the Fedify CLI, allowing users to define persistent settings in .fedifyrc or fedify.config.json files. This change also centralizes and refactors how command-line options are handled, establishing a clear precedence (CLI flags > config file > hardcoded defaults) to improve the CLI's clarity, maintainability, and overall user experience.

Highlights

  • Configuration System: Introduced a new configuration system that allows the Fedify CLI to load settings from .fedifyrc or fedify.config.json files, enabling persistent user-defined options.
  • Option Precedence: Established a clear hierarchy for option resolution: command-line flags take precedence over configuration file settings, which in turn override hardcoded defaults.
  • Centralized Option Handling: Refactored the CLI's core to include a globalAction in mod.ts that manages shared options and initializes resources like the cache directory, reducing duplication and improving consistency.
  • --no-config Flag: Added a --no-config flag to allow users to bypass the loading of configuration files, providing greater flexibility for scripting and testing.
  • Relocated Options: Moved several global options, such as --user-agent, to their respective subcommands (lookup, nodeinfo, webfinger) to make the CLI interface more intuitive and self-documenting.
  • Logging Improvements: Centralized log level management within the globalAction based on --debug and --verbose flags, ensuring consistent logging behavior across all commands.
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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

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 issue 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 or fill out our survey to provide feedback.

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.

@github-actions github-actions bot added component/cli CLI tools related difficulty/beginner Beginner friendly priority/medium Medium priority issues type/enhancement Improvements to existing features type/feature Requests for new features labels Aug 3, 2025
Copy link
Contributor

@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 a valuable configuration file system for the Fedify CLI, which significantly improves usability. The implementation is well-structured, particularly the centralized option handling. My review focuses on enhancing this new system by ensuring all defined configuration options are utilized, suggesting a more robust and maintainable approach for the --no-config flag, and addressing a couple of bugs and redundancies. These changes will help make the configuration feature more complete and reliable.

.globalAction(async (options) => {
const config = await loadConfig();
setSharedOptions(config);
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The --no-config flag is implemented on a per-command basis, which leads to some code duplication and a more complex implementation for sharing options. For better clarity, maintainability, and user experience, consider making --no-config a true global option.

This would involve:

  1. Adding .globalOption("--no-config [flag:boolean]", "Disable loading config file.") in mod.ts.
  2. Changing const config = await loadConfig(); to const config = options.noConfig ? {} : await loadConfig(); in the globalAction.
  3. Removing the --no-config option from all subcommands (lookup, nodeinfo, webfinger).
  4. Simplifying getSharedOption in packages/cli/src/utils.ts by removing the noConfig parameter, as the logic will be handled centrally.

Comment on lines 264 to 293
const collection = await lookupObject(url, {
documentLoader: authLoader ?? documentLoader,
contextLoader,
userAgent: options.userAgent,
userAgent: options.userAgent ??
getSharedOption("userAgent", options.noConfig),
});
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The timeout and followRedirects settings from the configuration file are not being applied when calling lookupObject. You should pass these options to ensure the CLI respects the user's configuration. For full consistency, you might also consider adding --timeout and --follow-redirects flags to this command.

      const collection = await lookupObject(url, {
        documentLoader: authLoader ?? documentLoader,
        contextLoader,
        userAgent: options.userAgent ??
          getSharedOption("userAgent", options.noConfig),
        timeout: getSharedOption("timeout", options.noConfig),
        followRedirects: getSharedOption("followRedirects", options.noConfig),
      });

Comment on lines 60 to 64
const nodeInfo = await getNodeInfo(url, {
parse: "none",
userAgent: options.userAgent,
userAgent: options.userAgent ??
getSharedOption("userAgent", options.noConfig),
});
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The timeout setting from the configuration file is not being used when calling getNodeInfo. Please pass it through to respect the user's configuration.

      const nodeInfo = await getNodeInfo(url, {
        parse: "none",
        userAgent: options.userAgent ??
          getSharedOption("userAgent", options.noConfig),
        timeout: getSharedOption("timeout", options.noConfig),
      });

Comment on lines 74 to 78
const nodeInfo = await getNodeInfo(url, {
parse: options.bestEffort ? "best-effort" : "strict",
userAgent: options.userAgent,
userAgent: options.userAgent ??
getSharedOption("userAgent", options.noConfig),
});
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The timeout setting from the configuration file is not being used when calling getNodeInfo. Please pass it through to respect the user's configuration.

    const nodeInfo = await getNodeInfo(url, {
      parse: options.bestEffort ? "best-effort" : "strict",
      userAgent: options.userAgent ??
        getSharedOption("userAgent", options.noConfig),
      timeout: getSharedOption("timeout", options.noConfig),
    });

Comment on lines 99 to 105
const response = await fetch(faviconUrl, {
headers: {
"User-Agent": options.userAgent == null
? getUserAgent()
: options.userAgent,
"User-Agent": options.userAgent ??
getSharedOption("userAgent", options.noConfig) ??
getUserAgent(),
},
});
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The followRedirects setting from the configuration file is not being applied to this fetch call. You can use this setting to control the redirect option for fetch.

        const response = await fetch(faviconUrl, {
          headers: {
            "User-Agent": options.userAgent ??
              getSharedOption("userAgent", options.noConfig) ??
              getUserAgent(),
          },
          redirect: getSharedOption("followRedirects", options.noConfig) === false
            ? "manual"
            : "follow",
        });

Comment on lines 40 to 45
const webFinger = await lookupWebFinger(url, {
...options,
userAgent: options.userAgent ??
getSharedOption("userAgent", options.noConfig),
}) ?? // Look up WebFinger
new NotFoundError(resource).throw(); // throw NotFoundError if not found
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The timeout setting from the configuration file is not being applied when calling lookupWebFinger. Please pass it through to respect the user's configuration.

Suggested change
const webFinger = await lookupWebFinger(url, {
...options,
userAgent: options.userAgent ??
getSharedOption("userAgent", options.noConfig),
}) ?? // Look up WebFinger
new NotFoundError(resource).throw(); // throw NotFoundError if not found
const webFinger = await lookupWebFinger(url, {
...options,
userAgent: options.userAgent ??
getSharedOption("userAgent", options.noConfig),
timeout: getSharedOption("timeout", options.noConfig),
}) ?? // Look up WebFinger
new NotFoundError(resource).throw(); // throw NotFoundError if not found

Copy link
Contributor

github-actions bot commented Aug 3, 2025

The docs for this pull request have been published:

https://f40f24dc.fedify.pages.dev

@devtedlee devtedlee marked this pull request as ready for review August 3, 2025 11:09
Copy link
Member

@dahlia dahlia left a comment

Choose a reason for hiding this comment

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

This behavior should be documented in the docs/cli.md file. It should include:

  • Paths where the fedify command looks for the configuration files (on Linux/macOS/Windows)
  • Available configuration fields
  • Who wins when there are different settings are provided through CLI options and configuration files
  • etc

- add Config interface for options
- add loadConfig function for load files like .fedifyrc and .fedify.config.json
- add tests for config.ts
- chore: remove duplicated std/assert package, and add std/path package

# Conflicts:
#	packages/cli/src/config.test.ts
#	packages/cli/src/config.ts
- apply logger at config.ts
- add global command options: userAgent, timeout, redirects, verbose, format, noConfig
- command option is higher priority than config file options

# Conflicts:
#	cli/mod.ts
The new approach introduces a single `globalAction` that:
- Checks for the `--no-config` flag to conditionally load external configuration.
- Merges options from different sources with the correct precedence:
  1. Command-line arguments
  2. Configuration file values
  3. Hardcoded defaults
- Initializes shared resources like the cache directory (`setCacheDir`) after all options have been resolved.
- apply this sharedOptions to lookup and webfinger
This commit overhauls the previously confusing global command-line options, relocating them to more appropriate subcommands. It also introduces a feature to bypass config file loading, enhancing the CLI's flexibility and testability.

Key changes include:

- Option Relocation: Removed global options like --user-agent and moved them to individual subcommands (lookup, nodeinfo, webfinger) for better clarity.
- '--no-config' Flag: Introduced a --no-config option to skip reading the configuration file. The getSharedOption utility has been updated to respect this flag.
- Improved Logging Logic: Centralized the log level configuration based on --debug and --verbose flags into the globalAction for more consistent handling.
- Code Simplification: Reducing global options has simplified the globalAction logic in mod.ts. Each subcommand is now responsible only for its own options, clarifying the structure.
- add 2 tests for config.test.ts
- mod.ts: remove unnecessary cache dir, add options.verbose override logic
- lookup.ts: add missing code for getSharedOption for userAgent
- remove vocab.ts file
- use 'options.config' instead of 'options.noConfig'
- fix by PR
- modify logtape log level to 'warning'
- add global option no-config
- at window: default AppData, if not use UserProfile
- at linux: defualt XDG_CONFIG_HOME, if not use Home
- fix failed tests
- add tests for os specific logic
- below contents added.
- global option for commands
- paths where the fedify command looks for the configuration files (on Linux/macOS/Windows)
- available configuration fields
- who wins when there are different settings are provided through CLI options and configuration files
Copy link
Contributor

github-actions bot commented Aug 4, 2025

The latest push to this pull request has been published to JSR and npm as a pre-release:

Package Version JSR npm
@fedify/fedify 1.8.1-pr.349.1313+66f81076 JSR npm
@fedify/cli 1.8.1-pr.349.1313+66f81076 JSR
@fedify/amqp 1.8.1-pr.349.1313+66f81076 JSR npm
@fedify/express 1.8.1-pr.349.1313+66f81076 JSR npm
@fedify/h3 1.8.1-pr.349.1313+66f81076 JSR npm
@fedify/nestjs 1.8.1-pr.349.1313+66f81076 npm
@fedify/postgres 1.8.1-pr.349.1313+66f81076 JSR npm
@fedify/redis 1.8.1-pr.349.1313+66f81076 JSR npm
@fedify/sqlite 1.8.1-pr.349.1313+66f81076 JSR npm
@fedify/testing 1.8.1-pr.349.1313+66f81076 JSR npm

Comment on lines +9 to +12
/** http request timeout */
timeout?: number;
/** auto follow redirects mode */
followRedirects?: boolean;
Copy link
Member

Choose a reason for hiding this comment

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

Hmm… those two fields are apparently used nowhere?

/** HTTP related configuration */
http?: HttpConfig;
/** Output format configuration */
format?: FormatConfig;
Copy link
Member

Choose a reason for hiding this comment

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

This field is not used either.

Copy link
Author

@devtedlee devtedlee Aug 4, 2025

Choose a reason for hiding this comment

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

yes, I also noticed that at PR description 'focus on review' section. I don't know where to use this fields precisely.

I think If we try to use this fields, we also modify other fedify related codes. like @fedify/fedify getDocumentLoader function

Copy link
Member

Choose a reason for hiding this comment

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

See also the writeObjectToStream() function which is used in the packages/cli/src/lookup.ts file.

@dahlia dahlia linked an issue Aug 5, 2025 that may be closed by this pull request
7 tasks
@dahlia dahlia added this to the Fedify 1.9 milestone Aug 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component/cli CLI tools related difficulty/beginner Beginner friendly priority/medium Medium priority issues type/enhancement Improvements to existing features type/feature Requests for new features
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add configuration file support to Fedify CLI
2 participants