firebase / firebase-tools

The Firebase Command Line Tools
MIT License
4.02k stars 934 forks source link

`functions.ignore` - pattern negation doesn't work. When ! is used then all the files are excluded. #2677

Open wujekbogdan opened 4 years ago

wujekbogdan commented 4 years ago

[REQUIRED] Environment info

firebase-tools: 8.10.0

Platform: macos 10.15.16

[REQUIRED] Test case

  1. Create a firebase.json file with the following content:
    {
    "functions": {
    "source": ".",
    "ignore": [
      "node_modules",
      "src",
      "tests",
      "*.js",
      "!my.js"
    ]
    }
    }
  2. run firebase deploy --only functions

[REQUIRED] Expected behavior

The ZIP package that's generated by this command should contain all files from the source directory except for: node_modules, src, all files with .js extension except for my.js file.

[REQUIRED] Actual behavior

The generated ZIP package is empty it just contains a .runtimeconfig.json file, which is added no matter what ignore pattern contains.

The problem is caused by pattern negation. Even If I create a file like this:

{
  "functions": {
    "source": ".",
    "ignore": [
      "!my.js"
    ]
  }
}

Then the ZIP package is empty - all files are ignored. Everything works fine as long as there is no pattern negation.

The documentation says that ignore features should work the same way how .gitignore works, but it's not the case. If ! is not supported then the documentation should be clear about it.


UPDATE: I've just found that patterns like .*/** also don't work - this pattern should exclude all files in directories that start with . (.git, .idea, etc), but it doesn't work.

google-oss-bot commented 4 years ago

This issue does not seem to follow the issue template. Make sure you provide all the required information.

joehan commented 4 years ago

Hi @wujekbogdan, thanks for reporting this! Looking through the code that implements this, I think i see the issue. This code uses Minimatch to filter out every path that matches at least one of the globs.

In your first example, since all files except for my.js match !my.js, and my.js matches *.js, these ignore globs cover all files. This case I think is working as intended - if the docs suggest that it should be working otherwise, we should definitely update them.

The second example you give that includes only !my.js should ignore everything except for paths with the basename my.js - however, I think our recursive implementation might be ignoring the entire directory that contains my.js before it ever gets to my.js. If this is the case, its definitely a bug.

The .*/** rule should ignore any top level directory starting with ., but based on the implementation, won't match someDirectory/.git. Out of curiosity, does the glob **/.*/** do what you wanted here?

It would also be helpful if you'd share the file tree of your project - that way, we can try to understand which glob is matching the files you expect to be included. Regardless, we'll look to update our documentation about this to be more exact - though similar, it seems like this works differently than .gitignore in some subtle ways.

wujekbogdan commented 4 years ago

So let me explain my use-case:

The directory structure looks more or less like this:

.
├── package.json
├── .npmrc
├── .github/
│   └── workflows/
│       └── unit-tests.yml
├── .idea/
│   └── lots_of_settings_files
├── node_modules
│   └── modules_dirs
├── dist/
│   └── index.js
├── src/
│   └── directories/
│       └── and/
│           └── files.js
├── tests/
│   ├── directories
│   └── and/
│       └── files.spec.js
├── lots_of_other-config.files
└── ...

My current firebase.json setup is:

{
  "functions": {
    "source": "dist"
  }
}

The code, compiled with Babel, goes to dist, so we need some pre-deployment scripts that copy package.json and .npmrc files into dist.

I'd like to get rid of these deployment scripts by changing the config to:

{
  "functions": {
    "source": "."
  }
}

After I did it, it turned out that firebase takes the entire root directory and compresses it into zip. All I need is just dist, package.json and .npmrc.

So I though I could use the ignore option (which is not documented for functions at all, btw, the only documentation that exists is for hosting).

So I started to experiment with the ignore option assuming that it works the same way gitignore works.

My idea was to blacklist everything and just whitelist: dist, package.json and .npmrc. So my initial setup was:

{
  "functions": {
    "source": ".",
    "ignore": [
      "*",
      "!dist/**",
      "!.npmrc",
      "!package.json",
    ]
  }
}

I tried tons of various setups but neither of these worked. If I put ANY negation pattern in the ignore section then everything gets ignored. No matter what the negation pattern is.


Out of curiosity, does the glob */./** do what you wanted here?

Yes.

mbleigh commented 4 years ago

What if you try brace expansion in a single command:

{
  "functions": {
    "source": ".",
    "ignore": ["!{dist/**,.npmrc,package.json}"]
  }
}
google-oss-bot commented 4 years ago

Hey @wujekbogdan. We need more information to resolve this issue but there hasn't been an update in 7 weekdays. I'm marking the issue as stale and if there are no new updates in the next 3 days I will close it automatically.

If you have more information that will help us get to the bottom of this, just add a comment!

wujekbogdan commented 4 years ago

What if you try brace expansion in a single command:

{
  "functions": {
    "source": ".",
    "ignore": ["!{dist/**,.npmrc,package.json}"]
  }
}

I forgot to mention that I also tried this technique but it gives the same results as using an array if patterns.

M3kH commented 3 years ago

I'm also running in the same issue.

I'm trying to make sure I can keep some node_modules that are locally installed due to the monorepo setup.

This how my firebase setting looks like:

{
    "functions": {
        "source": "server",
        "ignore": [
            "!{node_modules/icon-project/**}",
            "node_modules",
            ".git"
        ]
    }
}
conrado commented 3 years ago

the workaround for me was to be very explicit about what I was excluding rather than negating.. thankfully it was only the .yarn directory rather than the full node_modules/

it is particularly important to be able to include some hidden files, where most people try to ignore them all, if using yarn2 workspaces you may get different version of the package manager running on the functions deploy, which could break because of --frozen-lockfile

MatthewPatience commented 2 years ago

This issue seems to be applicable to firebase hosting as well.

joehan commented 2 years ago

Hi @MatthewPatience - looking through the codebase, this chunk of code is only ever used for Functions and Extensions. If you are experiencing a similar issue for hosting, can you open a separate issue on this repo?

joehan commented 2 years ago

Duplicate issue: https://github.com/firebase/firebase-tools/issues/4615

kroikie commented 2 years ago

@joehan should this be closed?

bkendall commented 2 years ago

Duplicate #4615

bkendall commented 2 years ago

Duplicate of #4615

bkendall commented 2 years ago

(ugh I hate that that's obvious and I never get it right)

conrado commented 2 years ago

I made a bad joke about this issue earlier.

This isn't a duplicate, it is the original ticket for getting ignore patterns to work.

Current workaround is to detail every ignore file.

Is the fix in Typescript?

MarceloNascc commented 1 year ago

Hi, I'm having the same issue using firebase-tools: 11.28.0.

Is there any other workaround but to detail every ignore file?

I need to ignore all files that start with a dot except .npmrc. Any idea guys?

apiverveHQ commented 2 months ago

Is there a workaround with this? Ticket seems to be open for the last 4 years? I am having the same problem with negation