carloscuesta / gitmoji-cli

A gitmoji interactive cli tool for using emojis on commits. 💻
https://www.npmjs.com/package/gitmoji-cli
MIT License
4.64k stars 207 forks source link

Commiting from project subfolder does not work #1196

Open izi-p opened 1 year ago

izi-p commented 1 year ago

Discussion

Hello,

I want to use gitmoji-cli in my project. I set up the gitmoji config in package.json file. When I commit from project root, where package.json file is located, everything works as expected.

However, when commiting from a subfolder of the project (for example, src folder), it does not find config and use the default config.

Am I doing something wrong or is this feature not available?

Thank you

Validations

carloscuesta commented 1 year ago

Hey!

Thanks for opening an issue, indeed it looks like a bug since we use the cwd to get the package.json therefore if you try to commit within a subdirectory it will not pick up the configuration and the fallback will be served instead.

See: https://github.com/carloscuesta/gitmoji-cli/blob/da817998793871c1a8a0eea550055e349044251c/src/utils/configurationVault/getConfiguration.js#L60

🤔 Thinking out loud, I'm not sure how other tools approach this but it's a fair use-case to think people can commit from subdirectories.

The problem is that if we want to implement this it can be tricky to start traversing each directory (up) until you find a file that contains a configuration file 😅

I think we should somehow get the absolute directory for the git repo and try to find the configuration files there instead of relying on the current working directory.

izi-p commented 1 year ago

Hey Carloscuesta

It looks like NPM does like this

Starting at the $PWD, npm will walk up the folder tree checking for a folder that contains either a package.json file, or a node_modules folder. If such a thing is found, then that is treated as the effective "current directory" for the purpose of running npm commands. (This behavior is inspired by and similar to git's .git-folder seeking logic when running git commands in a working dir.)

https://docs.npmjs.com/cli/v7/configuring-npm/folders

Maybe we can implement the same way as they do. We can also limit to a certain amount of folders to make sure the calculation does not take forever.

It's also important to note that for a monorepo, we usually commit in project subfolders (packages folders), but we might want a global gitmoji config for the whole project.

.gitmojirc.json
package.json
packages/
----my-package/
--------package.json
--------src/
----my-second-package/
--------package.json
--------src/

For this use case, we would need a global .gitmojirc.json file and recursively walking up folders to find it in the project root.

Pierre

izi-p commented 1 year ago

I ran into this PR as well, so it used to work maybe

https://github.com/carloscuesta/gitmoji-cli/pull/57

segersniels commented 1 year ago

There's definitely pretty straight forward ways to achieve this. Something like this should suffice to find either package.json with a gitmoji config or a .gitmojirc.json file:

import { execSync } from 'child_process';
import fs from 'fs';
import path from 'path';

function findWorkspaceRoot() {
  try {
    const stdout = execSync('git rev-parse --show-toplevel');

    return stdout.toString().trim();
  } catch (err) {
    return;
  }
}

enum ConfigType {
  Package = 'package.json',
  Config = '.gitmojirc.json',
}

function findConfigDir(type: ConfigType) {
  const root = findWorkspaceRoot();

  let currentDir = process.cwd();
  while (true) {
    const configPath = path.join(currentDir, type);
    if (fs.existsSync(configPath)) {
      if (type === ConfigType.Package) {
        const packageJson = JSON.parse(fs.readFileSync(configPath, 'utf8'));

        if (packageJson.gitmoji) {
          return currentDir;
        }
      } else {
        return currentDir;
      }
    }

    if (currentDir === (root ?? path.dirname(currentDir))) {
      break;
    }

    currentDir = path.dirname(currentDir);
  }

  throw new Error('Reached root without finding gitmoji config');
}

findConfigDir(ConfigType.Package);

Basically crawl up the parent directories until you find a directory that has a config file that is usable. In an ideal scenario git rev-parse --show-toplevel returns the top level of the repository. But if that fails it just crawls up the filesystem until / is reached.