Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(publish): make include and exclude work #22720

Merged
merged 14 commits into from
Mar 8, 2024

Conversation

dsherret
Copy link
Member

@dsherret dsherret commented Mar 5, 2024

  1. Stops deno publish using some custom include/exclude behaviour from other sub commands
  2. Takes ancestor directories into account when resolving gitignore
  3. Backards compatible change that adds ability to unexclude an exclude by using a negated glob at a more specific level for all sub commands (see feat: improve improve/exclude deno_config#44).

Include only deno/ folder

This respects the ignored files in the gitignore:

{
  "publish": [
    "include": ["deno/"]
  ]
}

Include all files except dist/ folder

This respects the ignored files in the gitignore:

{
  "publish": [
    "exclude": ["dist/"]
  ]
}

Include a file/directory that's excluded at the top level

{
  "publish": [
    "exclude": [
      "!dist" // unexclude for publish
    ]
  ],
  "exclude": [
    "dist"
  ]
}

Include a file/directory that's excluded in a gitignore

// gitignore
dist
{
  "publish": [
    "exclude": [
      "!dist" // unexclude for publish
    ]
  ]
}

Include all files except the dist/ folder, but do include dist/js/

{
  "publish": [
    "exclude": [
      "dist/",
      "!dist/js/", // items further down in the array win over items above
    ]
  ]
}

Closes #22648
Closes #22656
Closes #22482
Closes jsr-io/jsr#194

@dsherret
Copy link
Member Author

dsherret commented Mar 7, 2024

I'm working on updating deno-docs with this information.

@dsherret dsherret marked this pull request as ready for review March 7, 2024 17:38
@dsherret dsherret requested a review from bartlomieju March 7, 2024 21:57
@@ -1095,7 +1095,15 @@ impl Config {
continue;
};
let settings = self.workspace_settings_for_specifier(workspace_uri);
if settings.enable.unwrap_or_else(|| self.has_config_file()) {
Copy link
Member Author

Choose a reason for hiding this comment

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

@nayeemrmn this previous condition seemed slightly wrong and caused some trouble in the tests. Is the new condition ok?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah good find, but if enable_paths is specified then it should completely override enable.

if settings.enable_paths.as_ref().map(|p| !p.is_empty()).unwrap_or_else(|| previous_condition) { ... }

cli/tools/bench/mod.rs Show resolved Hide resolved
cli/tools/registry/tar.rs Show resolved Hide resolved
cli/util/fs.rs Outdated Show resolved Hide resolved
let dir_path = if is_dir { &c } else { c.parent()? };
git_ignores.get_resolved_git_ignore(dir_path)
});
if !is_pattern_matched(
Copy link
Member

Choose a reason for hiding this comment

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

This whole for loop + loop is super hard to grasp. Consider rewriting to use if + continue, but not a blocker to land

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm going to leave the code as-is for now because doing that is a riskier refactor.

Copy link
Member

Choose a reason for hiding this comment

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

Is this whole module added just to support testing gitignore functionality? 😬 If so consider making it only available in cfg(test)

Copy link
Member Author

Choose a reason for hiding this comment

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

Can't make it #[cfg(test)] because then it can't be used outside this crate. I think this will just be optimized away when compiling?

Copy link
Member

Choose a reason for hiding this comment

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

Hm... Since the trait it implements is public maybe move it to the gitignore module?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it would be useful in the future for non-CLI crates and Deploy for testing purposes.

@@ -0,0 +1,424 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

#![allow(clippy::disallowed_types)]
Copy link
Member

Choose a reason for hiding this comment

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

Are there many of them? Maybe leave a comment about this directive usage.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm going to add a comment on this. It's just to use Arc, which is fine for this module.

@dsherret dsherret requested a review from bartlomieju March 7, 2024 23:16
@dsherret dsherret merged commit 2dfc0ac into denoland:main Mar 8, 2024
17 checks passed
@dsherret dsherret deleted the fix_publish_include_exclude branch March 8, 2024 01:16
@ghostdevv
Copy link

ghostdevv commented Mar 8, 2024

The behaviour of include respecting the .gitignore even when you specifically ask it to include a file that has been ignored feels very unintuitive to me - but perhaps I am missing something? To me the include option here feels more specific than the gitignore and should be able to overwrite it - or I should have to do the ! syntax in the include not the exclude

dsherret added a commit that referenced this pull request Mar 8, 2024
@dsherret
Copy link
Member Author

dsherret commented Mar 8, 2024

@ghostdevv there are so many scenarios with what files should be matched or not. For example, someone might specify the ./src folder and expect gitignored files/directories within that folder to not be matched. Someone else might expect them to be matched. Perhaps someone does ./**/*.json in their include, but they have one .gitignored json file they didn't want included, but someone else in a similar situation did. So the behaviour implemented in this PR is to not include anything that's gitignored for people that want that behaviour, but also providing an explicit opt-out mechanism for people who want to include something that's gitignored.

Also, another point is that "include" is a closed set. The opt-out mechanism works when only specifying "exclude" as well.

That said, and as you allude to, directories or files (non-globs) in the include array should override non-glob .gitignore entries that match the full path or an ancestor directory. I thought it would be complicated to implement because of directories, but I thought of an easy way to implement it. Opened #22790

littledivy pushed a commit that referenced this pull request Mar 8, 2024
1. Stops `deno publish` using some custom include/exclude behaviour from
other sub commands
2. Takes ancestor directories into account when resolving gitignore
3. Backards compatible change that adds ability to unexclude an exclude
by using a negated glob at a more specific level for all sub commands
(see denoland/deno_config#44).
littledivy pushed a commit that referenced this pull request Mar 8, 2024
@magic-akari
Copy link

magic-akari commented Mar 8, 2024

I expect that using exclude similar to .npmignore would completely override .gitignore, but that's not the case in practice.
It seems that deno/jsr still follows the .gitignore file as a base and then applying additional exclude rules on top of it.

The situation I encountered is that the .gitignore file is generated by other tools in subdirectories, such as wasm-bindgen, so it is not advisable to modify it. Additionally, the negation exclude: ["!*"] does not take effect.

Is there a way to completely override .gitignore to only enable exclude, making it behave more like .npmignore?

cd pkg
npx jsr publish --dry-run
# pkg/.gitignore
*
# pkg/.npmignore
*.tgz
{
  "exclude": []
}

@dsherret
Copy link
Member Author

dsherret commented Mar 8, 2024

Oh, that's strange. The negation should work, but it looks like it doesn't. Seems like it only works if I explicitly specify the files or directories at the top level. I'm looking into it.

@dsherret
Copy link
Member Author

dsherret commented Mar 8, 2024

@magic-akari ok, so the reason it occurs in that scenario is because the .gitignore has * and so it ignores the parent directory. It looks like that's a bug and * in a gitignore should not ignore the parent directory (seems to only occur for the root folder). Real life scenarios that don't use * in a .gitignore should work.

Also, you'll probably want to use !** (matches all files including in descendent directories) and not just !* (only matches stuff in the cwd)

dsherret added a commit that referenced this pull request Mar 8, 2024
#22805)

This is an unrealistic scenario, but it's still a good thing to fix and
have a test for because it probably fixes some other underlying issues
with how the gitignore was being resolved for the root directory.

From #22720 (comment)
@ghostdevv
Copy link

@dsherret that makes a lot of sense thanks! It's for sure a complicated problem and this is probably the nicest solution

nathanwhit pushed a commit that referenced this pull request Mar 14, 2024
#22805)

This is an unrealistic scenario, but it's still a good thing to fix and
have a test for because it probably fixes some other underlying issues
with how the gitignore was being resolved for the root directory.

From #22720 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants