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

Adds FilesLinter that makes sure all required files are available #6069

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

mustiikhalil
Copy link
Collaborator

@mustiikhalil mustiikhalil commented Mar 12, 2024

Short description 📝

Adds FilesLinter that makes sure that all non-glob files would would present warnings

Resolves #5552

How to test the changes locally 🧐

The command should be useable through out the entire project, however to test this following the steps below would be the best approach:

  • Go to fixtures that's missing resources, or sources.
  • Running tuist generate --no-open should flush a lot of warnings which is to be expected

Output

...
The following warnings need attention:
 · No files found at: /ios_app_with_framework_and_missing_resources/App/Resources/**/*.png
 · No files found at:/ios_app_with_framework_and_missing_resources/App/Resources/*.xcassets
 · No files found at:/ios_app_with_framework_and_missing_resources/StaticFramework/Resources/images/t.txt
 · The target StaticFramework doesn't contain source files.
 · No files found at: /ios_app_with_framework_and_missing_resources/StaticFramework/Resources/images/**/*.png
 ...
  • Running tuist generate --no-open should flush non-glob warnings as shown below

Output

�[33m · No resources found at: Resources/images/t.txt
 · No files found at: Sources/App+internals.swift
 · The target StaticFramework doesn't contain source files.�[0m

Contributor checklist ✅

  • The code has been linted using run mise run lint:fix
  • The change is tested via unit testing or acceptance testing, or both
  • The title of the PR is formulated in a way that is usable as a changelog entry
  • In case the PR introduces changes that affect users, the documentation has been updated

Reviewer checklist ✅

  • The code architecture and patterns are consistent with the rest of the codebase
  • Reviewer has checked that, if needed, the PR includes the label changelog:added, changelog:fixed, or changelog:changed, and the title is usable as a changelog entry

@mustiikhalil
Copy link
Collaborator Author

I wonder

  1. how or where should I document the changes?
  2. And if unit tests are actually needed in this case?

@mustiikhalil mustiikhalil self-assigned this Mar 12, 2024
@danieleformichelli
Copy link
Collaborator

I don't think we should blindly suppress warnings, but rather allow suppressing a specific instance of it.
Otherwise you can just ignore the output and you are good 😁

@mustiikhalil
Copy link
Collaborator Author

@danieleformichelli okay, then how do we identify or specify which warnings a developer would want to suppress? what I mean by that is do we separate the types of warnings within tuist into different domains and then run it somewhat like this --suppress-warnings lint missing-files?

@danieleformichelli
Copy link
Collaborator

@danieleformichelli okay, then how do we identify or specify which warnings a developer would want to suppress? what I mean by that is do we separate the types of warnings within tuist into different domains and then run it somewhat like this --suppress-warnings lint missing-files?

For this specific case, I think it should be a target property whether to ignore if it has ick m invalid sources or not

@mustiikhalil
Copy link
Collaborator Author

Wouldn't that go against why we would want to add suppress the warnings? For example, on local development machines we would want to suppress warnings, but not on the CI.

@danieleformichelli
Copy link
Collaborator

danieleformichelli commented Mar 13, 2024

Wouldn't that go against why we would want to add suppress the warnings? For example, on local development machines we would want to suppress warnings, but not on the CI.

When have we decided that it was the why? :)
I would suggest discussing the matter on slack or a github discussion before jumping into implementation 🙏

My PoV is that ususally it's a good warning. There might be some cases (like the template mentioned in the issue) where it might be annoying, hence we should allow to disable it only for targets created from that template

@mustiikhalil
Copy link
Collaborator Author

Sounds good, i'll move this discussion into slack later today! thanks for your input

@mustiikhalil mustiikhalil force-pushed the issue-5552 branch 2 times, most recently from 5dda4a9 to 979cf0b Compare March 16, 2024 14:30
@mustiikhalil mustiikhalil marked this pull request as ready for review March 16, 2024 16:23
@mustiikhalil mustiikhalil changed the title Adds Suppress warnings flag to TuistCommand Adds FilesLinter that makes sure all required files are available Mar 16, 2024
Copy link
Member

@fortmarek fortmarek left a comment

Choose a reason for hiding this comment

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

Thanks a lot for the PR! However, I think we should move the linting from the loading phase to the generation phase instead to align with other linters we already have in the codebase.

Comment on lines 29 to 32
if !path.pathString.isGlobComponent {
// FIXME: This should be done in a linter.
logger.warning("No files found at: \(path.pathString)")
}
Copy link
Member

Choose a reason for hiding this comment

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

Why have we not moved this to the new linter?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Code wise this just needs to be removed, the linter already does this


@testable import TuistLoader

class FilesLinterTests: XCTestCase {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
class FilesLinterTests: XCTestCase {
final class FilesLinterTests: XCTestCase {

func lint(project: LoadedWorkspace, convertedProjects: [TuistGraph.Project]) -> [LintingIssue]
}

public class FilesLinter: FilesLinting {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public class FilesLinter: FilesLinting {
public final class FilesLinter: FilesLinting {

let results = subject.lint(project: workspace, convertedProjects: [graphProject])

// Then
XCTAssertTrue(results.contains(LintingIssue(
Copy link
Member

Choose a reason for hiding this comment

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

You can use XCTContainsLintingIssue

I would also assert the number of issues

Copy link
Member

Choose a reason for hiding this comment

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

Can we also test that a glob for which no files exist does not throw a warning?

Comment on lines 151 to 155
let filesLintingIssues = filesLinter.lint(
project: allManifests,
convertedProjects: projectsModels
)
filesLintingIssues.printWarningsIfNeeded()
Copy link
Member

Choose a reason for hiding this comment

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

Why is this linted here and not along with all the other linters we have here? This could probably be added as a TargetLinter. I don't really see a reason why this needs to be linted during the load phase.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, so i tried to looking into that, however it seems that we cant really put it there since we require the allManifests and that's being fetched within the same function. and the linter itself compares the paths between, the generated targets from the allManifests to the actual allManifests

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Or do you think there is a better option there @fortmarek?

Copy link
Contributor

Choose a reason for hiding this comment

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

Considering the need "I need linters to know whether a file has been derived from a glob", you need:

  1. A way to express that
  2. Use that information from the linters that @fortmarek pointed out.

We already have a module that represents a path. You can extend it to include information about whether it came from a glob:

public enum FileElement: Equatable, Hashable, Codable {
    case file(path: AbsolutePath, metadata: Set<FileElementMetadata>)
    case folderReference(path: AbsolutePath, metadata: Set<FileElementMetadata>)
}

// Somewhere in the mapping logic.
FileElement.path("....", metadata: [.fromGlob])

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Okay nice then, I'll take a look at it and see if that's going to work as expected

Copy link
Member

Choose a reason for hiding this comment

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

I've been wondering, do we need the extra metadata? If we decide that we won't show any warnings when no files match a glob but we still want to show a warning for individual files, can't we only lint the individual files exist? As we don't add the parent glob directory if the glob doesn't match anything.

Copy link
Contributor

Choose a reason for hiding this comment

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

can't we only lint the individual files exist?

That's the idea, but how do you know at the linter level if a file or not was hardcoded by the user or resolved from a glob without passing that information when the models are mapped from ProjectDescription to TuistGraph?

Copy link
Member

Choose a reason for hiding this comment

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

When we resolve a glob, we then pass on only files that the file system can find. How would a non-existing file from a glob be added as a regular file?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'll resume the work on this weekend, or the weekend after. I've been super busy lately.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hey, If possible, I would love to get some feedback regarding the approach that was taken before adding tests and basically moving forward with this PR.

Copy link
Contributor

@pepicrft pepicrft left a comment

Choose a reason for hiding this comment

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

Thanks a lot for taking the lead here @mustiikhalil. I think we should move this to the existing linters, and make any necessary changes to allow that solution.

@mustiikhalil mustiikhalil force-pushed the issue-5552 branch 3 times, most recently from c9547a7 to adc7d4b Compare April 11, 2024 15:52
Comment on lines 324 to 355
if target.supportsResources {
let files = target.copyFiles.flatMap(\.files)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We can lint based on glob, and folder reference too, but for now I made it simple for the sake of reviewing it

Comment on lines 34 to 38
public var sourcesPaths: [AbsolutePath]
public var resources: ResourceFileElements
public var resourcesPaths: [AbsolutePath]
public var copyFiles: [CopyFilesAction]
public var copyFilesPaths: [AbsolutePath]
Copy link
Member

@fortmarek fortmarek Apr 16, 2024

Choose a reason for hiding this comment

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

Do we actually need to track these paths in extra properties? Can't we lint that the files added do exist based on directly the sources, resources, and copyFiles properties?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Well, i tried to make it work but couldnt since we kinda need to find a point of reference. For example, /app/sources/text.swift will not show up in the sources if its not within the directory. So we kinda need to store the paths to compare them later on in the linter.

Copy link
Member

Choose a reason for hiding this comment

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

There should be a place where we skip adding files to sources when they don't exist. Maybe we can try including them? Would be interesting to see what happens as that should be a valid operation in Xcode.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@fortmarek so I updated the code to remove all of those and simply just allow tuist to append all the files into Xcode. And then use the TargetLinter to display if there are any missing folders or files.

If this is the way to progress, I will add the tests and finalize the code for it

@mustiikhalil
Copy link
Collaborator Author

@fortmarek if you have time to review it so we can move forward towards getting this PR merged.

Creates a file linter that check if all non-glob Files within the
targets are available within the generated targets and project

Moves File validation into the TargetLinter as discussed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Remove annoying warning "No files found at:" for glob path
4 participants