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: consistent colors for packages #9008

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

Shaharking
Copy link
Contributor

PR Description

This PR addresses issue #2564 tagged as a good first issue.

Changes:

  • Used hashing on the package name to ensure consistent color assignment.
  • Expanded the color set for better distinction.

Additional Notes:

  • I encountered challenges running all the integration tests and was unable to figure out how to execute the turborepo-tests. It might be beneficial to provide a more detailed explanation of the testing process in the CONTRIBUTING.md file to assist future contributors.

Testing Instructions

  • The tests today already cover everything

@Shaharking Shaharking requested a review from a team as a code owner August 14, 2024 15:17
@turbo-orchestrator turbo-orchestrator bot added needs: triage New issues get this label. Remove it after triage owned-by: turborepo labels Aug 14, 2024
Copy link

vercel bot commented Aug 14, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

6 Skipped Deployments
Name Status Preview Comments Updated (UTC)
examples-basic-web ⬜️ Ignored (Inspect) Visit Preview Aug 16, 2024 11:58am
examples-designsystem-docs ⬜️ Ignored (Inspect) Visit Preview Aug 16, 2024 11:58am
examples-native-web ⬜️ Ignored (Inspect) Visit Preview Aug 16, 2024 11:58am
examples-svelte-web ⬜️ Ignored (Inspect) Visit Preview Aug 16, 2024 11:58am
examples-tailwind-web ⬜️ Ignored (Inspect) Visit Preview Aug 16, 2024 11:58am
examples-vite-web ⬜️ Ignored (Inspect) Visit Preview Aug 16, 2024 11:58am

Copy link

vercel bot commented Aug 14, 2024

@ShaharAdskAcc is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Member

@chris-olszewski chris-olszewski left a comment

Choose a reason for hiding this comment

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

Thank you for the PR! Do not worry about the integration tests, those will run on CI.

I think what we want is to keep the existing colors, but to hand them out in a consistent way while also making use of all the available colors i.e. not assigning 2 tasks the same color if there's still colors without any tasks.

To be frank, the current setup is overly complicated as it happens during the graph walk which is non-deterministic. I would suggest:

for task in engine.tasks().sorted() {
   self.color_cache.color_for_key(&task.to_string());
}
  • Then also switch so we select colors with the task id as well here

Comment on lines +14 to +17
let colors: [Style; u8::MAX as usize] =
core::array::from_fn(|index| Style::new().color256(index as u8));

colors
Copy link
Member

Choose a reason for hiding this comment

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

I don't believe we want to use all of the available colors as:

  • many of them aren't especially nice to look at
  • many of the colors are very similar e.g. in my tests I got 4 very similar shades of red
Screenshot 2024-08-14 at 1 32 23 PM

Copy link
Member

Choose a reason for hiding this comment

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

I'm still opposed to using all of the colors here for the reasons listed above.

We can expand our list in a separate PR, but we need to make sure the colors selected are easy to read in most terminals.

@Shaharking
Copy link
Contributor Author

Shaharking commented Aug 15, 2024

Got it @chris-olszewski.

I see that you suggested using the sorted task name to choose a color and caching it in a hashmap to ensure consistent color assignment. A straightforward approach would be to use an index and increment it each time we need a color for a new task.

Since the tasks are ordered by name, this method will generally guarantee the same color for a monorepo that doesn't change much.

However, if the order changes—like when adding or removing a package—there’s a good chance the colors will no longer match.

We could take a more complex approach to ensure consistent colors even when new packages are added. This could involve hashing the task name and using the result modulo the number of unused colors.

(hash % unused_colors.len())

The number of available colors decreases each time a color is assigned. Once all colors are used, we start again with the full color collection.

I think that for new projects that add lots of packages and change frequently, this feature might not be very beneficial. While approach 2 is a bit more complicated, it's still straightforward enough. I’m inclined to go with this approach—let me know your thoughts.

-Edit-
A slightly different approach that handles it a bit better -
We use an array of occupied / not occupied colors - when color taken in (hash % number of colors) ->
Then we try to take the next color (until found)

That is what I ended up using it.

@Shaharking
Copy link
Contributor Author

Hey @chris-olszewski,

I've updated the PR to include the following:

  • Prepopulating the color cache: All keys are now prepopulated when we start the walk, as suggested.
for task in engine.tasks().sorted() {
    self.color_cache.color_for_key(&task.to_string());
}
  • Selecting colors using the task ID: I’ve also switched the color selection to use the task ID, as recommended here.

Regarding the issue of similar colors: What do you suggest? We could limit the palette to more distinct colors, but this might result in more frequent repetition.

Copy link
Member

@chris-olszewski chris-olszewski left a comment

Choose a reason for hiding this comment

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

Just the visitor.rs changes in this PR are a huge improvement:

  • color order is no longer tied to task execution order
  • color is no longer tied to task hashes which change frequently

I would prefer to merge these improvements as they will make life better for many developers. As you mentioned there are still issues with tasks being added/removed from the graph, but that can be addressed in future PRs.

If you would move the changes to color_selector.rs to a new PR, then I would happily merge the remaining changes.

Comment on lines +14 to +17
let colors: [Style; u8::MAX as usize] =
core::array::from_fn(|index| Style::new().color256(index as u8));

colors
Copy link
Member

Choose a reason for hiding this comment

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

I'm still opposed to using all of the colors here for the reasons listed above.

We can expand our list in a separate PR, but we need to make sure the colors selected are easy to read in most terminals.

hasher.finish()
}

fn get_color_id_by_key(&mut self, key: &str) -> usize {
Copy link
Member

Choose a reason for hiding this comment

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

This implementation suffers from the same issue as the existing one where adding/removing tasks will result in a changed color for the task when there are hash collisions. If both a#build and b#build get the same initial color_id, then removing a#build will result in b#build changing colors.

Given we're targeting such a small hash (5 at the moment, 256 if we allow for all colors) hash collisions are fairly likely.

@Shaharking
Copy link
Contributor Author

Sure @chris-olszewski,
Here I created a seprate pr
#9023

@Shaharking
Copy link
Contributor Author

@chris-olszewski
I think we can increase the palette to 14 distinct colors. You can check out these references for more information:

https://superuser.com/questions/783656/whats-the-deal-with-terminal-colors
https://askubuntu.com/questions/1305637/what-do-the-colors-in-a-terminal-color-scheme-correspond-do
https://github.com/mbadolato/iTerm2-Color-Schemes

I excluded black because most users use it as their background color.

This change should reduce color collisions between packages, and having 14 colors, as opposed to 5, should make it easier to visually distinguish issues.

@Shaharking
Copy link
Contributor Author

Hey @chris-olszewski, is increasing the number of colors worth pursuing, or do you prefer to skip it? I'm unsure whether to continue testing different colors due to the lack of response.

@ijjk
Copy link
Member

ijjk commented Aug 22, 2024

Allow CI Workflow Run

  • approve CI run for commit: 46f49c4

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

1 similar comment
@ijjk
Copy link
Member

ijjk commented Aug 22, 2024

Allow CI Workflow Run

  • approve CI run for commit: 46f49c4

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs: triage New issues get this label. Remove it after triage owned-by: turborepo
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants