feat(core): natively support .dockerignore#10922
Conversation
rix0rrr
left a comment
There was a problem hiding this comment.
Thanks for doing all this hard work! Got a few minor comments on the implementation, but overall I like where this is going.
On the topic of trust: we've made changes here before and then accidentally broke people. How solidly do you feel about this implementation? And convince me how that's justified please? 😅
|
|
||
| let ignoreMode = props.ignoreMode || IgnoreMode.DOCKER; | ||
|
|
||
| if (ignoreMode != IgnoreMode.DOCKER) { |
There was a problem hiding this comment.
Why this restriction? I am okay with the default being DOCKER, but can't we support the old ones as well in case people depend on it?
There was a problem hiding this comment.
The reason I originally did this is because it feels plain wrong to process .dockerignore patterns with anything other than IgnoreMode.DOCKER.
This is the core thing that relates to the questions of backward compatibility, meaning, I'm not super confident how existing user-supplied exclude patterns will behave when flipped from the current IgnoreMode.GLOB (minimatch) to IgnoreMode.DOCKER, because both have different nuanced behavior.
So with this in mind, in the event that users may have become inadvertently dependent on the current broken behavior, maybe it is a good idea to still allow that old behavior as an option. Must we go even further and leave legacy as the default, with IgnoreMode.DOCKER as opt-in? It would be safest, though it would leave major out-of-the-box ergonomics on the table.
See 2f0b88f where I removed the restriction.
Another option is to default ignoreMode to the legacy IgnoreMode.GLOB if exclude was passed by the user but ignoreMode wasn't, since it likely means that they may be dependent on the legacy behavior.
Then again, maybe just letting users opt back into the legacy behavior if they run into issues is good enough. What do you think?
There was a problem hiding this comment.
I went a little more into this in the comment below.
| !Dockerfile | ||
| !.dockerignore |
There was a problem hiding this comment.
Remove these two since they're implicit, no?
| import { nodeunitShim, Test } from 'nodeunit-shim'; | ||
| import { IgnoreStrategy } from '../../lib/fs'; | ||
|
|
||
| nodeunitShim({ |
There was a problem hiding this comment.
Can I ask you to rewrite these to Jest tests and to use expect(...).toEqual(...) ? It'll generate better error messages.
In fact, I think I'd like to see tests of the form:
describe('globIgnorePattern', () => {
test('excludes nothing by default', () => {
const ignore = IgnoreStrategy.glob([]);
expect(filterFiles(ignore, [
'some/file/path',
]).toEqual([
'some/file/path',
]);
});
});
function filterFiles(strat: IgnoreStrategy, files: string[]) {
return files.filter(file => !strat.ignores(file));
}Feels like this would produce understandable outputs if the tests fail for some reason.
| * @param filePath file path to be assessed against the pattern | ||
| * @returns `true` if the file should be ignored | ||
| */ | ||
| public abstract ignores(filePath: string): boolean; |
There was a problem hiding this comment.
For all of these ignore functions, I'd like very much to be very clear about the expectations of absoluteness/relativeness of these file paths.
It seems like right now you're implicitly expecting all paths to be relative to the directory that contains the ignore file.
Please be very clear about that, documentation-wise, and add assertions/checks wherever it makes sense: reject absolute paths, etc.
Or, add in a way to normalize paths which can handle both absolute and relative. Or, expect absolute and relativize before checking. As long as the contract is very very clear.
There was a problem hiding this comment.
I agree. The root path against which paths passed to ignores() were being relativized was an implicit dependency of an IgnoreStrategy.
See fe58be1
I made this an explicit dependency. All paths are expected to be absolute paths. This is documented and reflected in the variable naming. I also throw exceptions if relative paths are passed where absolute paths are expected (which is everywhere in this PR).
IgnoreStrategy and the .ignores() method will take absolute paths. The absolute path passed to .ignores() is relativized against the absolute root path passed to IgnoreStrategy.
I went a little over this in the section on Backward Compatibility in the original post. Note: To be clear, everything here that follows is specifically concerning I am confident about the implementation because it's pretty much entirely delegating to packages that purely focus on implementing this behavior, compared to currently mashing I am not super confident about what would happen if we have user-supplied The reason this matters is because ideally we would make The consequences of differing matching behavior is:
(On the flip side, it may help to keep in mind and consider that we're already witnessing something like this, where we're processing In the first case, this would mean that the resulting asset is a little bloated. (Are there other security concerns?) In the second case, this would mean that some downstream process would be missing a file that it requires (e.g. to build the docker image). That is, downstream could break. The options I see are:
I think users, especially future users, would most benefit from having However, I recognize that you all may want to take a more conservative approach, in which case it seems like the second option is the only option. I'll be thinking about the third option because it may get us the best of both worlds: default Hopefully I've explained the situation well enough, but if not please let me know if you'd like some rephrasing or elaboration. I'm also happy to hear of other options that may not have occurred to me. |
|
I think to be safe I'm going to add a feature flag to trigger the new behavior. EDIT: Before we do that, I'm trying to reason through the consequences. The biggest issue I can see is how files that used to be present would now be missing, as that would lead users to deploying broken applications. It's hard to predict whether or not this will break users, and it seems critical. The flag is probably the safe way to go. |
|
@blaenk how do you feel about the current proposal? |
Agreed. I don't know for sure that this can happen, but it seems like a possibility. I agree with you that it's probably best to keep it as a feature flag, I totally forgot that CDK had that concept. It seems like the best approach:
I think that's the best we can hope for, and actually seems reasonable to me. |
|
Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
|
Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
Patterns in
.dockerignoreused to be interpreted as globs, which has different behavior from how.dockerignoreis supposed to be interpreted. Specifically it was hard to properly ignore whole directories at once (such as a largenode_modules).This PR adds an
ignoreModeflag which controls how the ignore patterns should be interpreted. The choices are:IgnoreMode.GLOB- interpret as beforeIgnoreMode.GIT- interpret as in.gitignoreIgnoreMode.DOCKER- interpret as in.dockerignoreUsers might have dependencies on the current behavior, which is why the default
ignoreModedepends on a feature flag:@aws-cdk/aws-ecr-assets:dockerIgnoreSupport(which is set totruefor new projects) enables the new, correct Docker-ignore behavior by default.Closes #10921
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license