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 broken table when no branches available (detached HEAD on checkout) #4426

Merged
merged 9 commits into from
Aug 9, 2023

Conversation

julieg18
Copy link
Contributor

@julieg18 julieg18 commented Aug 4, 2023

@julieg18 julieg18 added the bug Something isn't working label Aug 4, 2023
@julieg18 julieg18 self-assigned this Aug 4, 2023
@julieg18 julieg18 marked this pull request as ready for review August 4, 2023 23:14
for (const branch of branches) {
if (branch.includes(noBranchText)) {
const sha = await this.revParseHead(cwd)
parsedBranches.push(branch.replace(noBranchText, sha))
Copy link
Member

Choose a reason for hiding this comment

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

[C] We now have two sets of logic. One here and one at:

const cleanBranch = branch
.replace('* ', '')
.replace(/\(HEAD\s\w+\s\w+\s/, '')
.replace(')', '')

Maybe that is ok but it would be good to pull out constants like HEAD & (no branch) as they may serve as breadcrumbs later. We could also move isCurrentBranch into the git folder.

A good practice would be to (generally) encapsulate all of the logic in the same place. I've tried to leave the reader as dumb as possible previously and not put any transformation logic in here at all (an exception being trim and split). The reason for encapsulation is that in future when things inevitably break we won't be searching through the code to work out all of the possible places something has been changed.

With all of that said maybe the correct place for this logic is in:

private async updateBranches() {
const allBranches = await this.internalCommands.executeCommand<string[]>(
AvailableCommands.GIT_GET_BRANCHES,
this.dvcRoot
)
this.experiments.setBranches(allBranches)
}

after calling setBranches check the current branch and overwrite with revParseHead if it matches (no branch) this is a special case so we should still avoid calling revParseHead if necessary.

Does all of that make sense?

Copy link
Member

Choose a reason for hiding this comment

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

Another (more involved) way of fixing the issue is assuming that these commands:

const [branchLog, totalCommits] = await Promise.all([
this.internalCommands.executeCommand(
AvailableCommands.GIT_GET_COMMIT_MESSAGES,
this.dvcRoot,
branch,
String(nbOfCommitsToShow)
),
this.internalCommands.executeCommand<number>(
AvailableCommands.GIT_GET_NUM_COMMITS,
this.dvcRoot,
branch
)
])

will work if we don't pass a branch to them (needs tested). We could then leave the detached HEAD/no branch strings as is (I think) and not pass a branch for the current branch. If this all worked as expected it should lead to a slightly better UX of showing the original branch name in the experiments table (e.g (no branch) so that they user knows that they currently don't have a branch to work with.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does all of that make sense?

Yes, makes sense! I'll move this branch parsing logic to updateBranches.

will work if we don't pass a branch to them (needs tested). We could then leave the detached HEAD/no branch strings as is (I think) and not pass a branch for the current branch. If

Did a quick test and GIT_GET_NUM_COMMITS needs a branch to work with.

Copy link
Member

Choose a reason for hiding this comment

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

GIT_GET_NUM_COMMITS <= could this use HEAD?

Copy link
Member

@mattseddon mattseddon Aug 9, 2023

Choose a reason for hiding this comment

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

Making these updates seems to work (rough):

  private async updateExpShow() {
    await this.updateBranches()
    const [currentBranch, ...branches] = this.experiments.getBranchesToShow()
    const availableNbCommits: { [branch: string]: number } = {}

    const promises = []

    promises.push(
      this.collectGitLogByBranch(currentBranch, availableNbCommits, true)
    )

    for (const branch of branches) {
      promises.push(this.collectGitLogByBranch(branch, availableNbCommits))
    }

    const branchLogs = await Promise.all(promises)
    const { args, gitLog, rowOrder } = this.collectGitLogAndOrder(branchLogs)

    const expShow = await this.internalCommands.executeCommand<ExpShowOutput>(
      AvailableCommands.EXP_SHOW,
      this.dvcRoot,
      ...args
    )

    this.collectFiles({ expShow })
    return { availableNbCommits, expShow, gitLog, rowOrder }
  }

  private async collectGitLogByBranch(
    branch: string,
    availableNbCommits: { [branch: string]: number },
    isCurrent?: boolean
  ) {
    const nbOfCommitsToShow = this.experiments.getNbOfCommitsToShow(branch)

    const [branchLog, totalCommits] = await Promise.all([
      this.internalCommands.executeCommand(
        AvailableCommands.GIT_GET_COMMIT_MESSAGES,
        this.dvcRoot,
        isCurrent ? 'HEAD' : branch,
        String(nbOfCommitsToShow)
      ),
      this.internalCommands.executeCommand<number>(
        AvailableCommands.GIT_GET_NUM_COMMITS,
        this.dvcRoot,
        isCurrent ? 'HEAD' : branch
      )
    ])

    availableNbCommits[branch] = totalCommits

    return {
      branch,
      branchLog: isCurrent ? branchLog.replace('HEAD', branch) : branchLog
    }
  }

...

  private async updateBranches() {
    const allBranches = await this.internalCommands.executeCommand<string[]>(
      AvailableCommands.GIT_GET_BRANCHES,
      this.dvcRoot
    )

    const { currentBranch, branches } = collectBranches(allBranches)

    this.experiments.setBranches(branches, currentBranch)
  }


image

This would also mean we could remove env: { LANG: 'en_US.UTF-8' } from the GitReader.

Happy to pick up this second change if I won't be stepping on your toes.

Copy link
Member

Choose a reason for hiding this comment

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

note: also need to update collectBranches:

    const cleanBranch = branch.replace('* ', '')
    // .replace(new RegExp(`\\(${gitPath.DOT_GIT_HEAD}\\s\\w+\\s\\w+\\s`), '')
    // .replace(')', '')

Copy link
Contributor Author

@julieg18 julieg18 Aug 9, 2023

Choose a reason for hiding this comment

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

Ohhhhhh, ok, I understand your solution idea a lot better, thanks! I'll apply your changes + add tests.

@mattseddon mattseddon changed the title Fix broken table on detached HEAD Fix broken table when no branches available (detached HEAD on checkout) Aug 6, 2023
Copy link
Contributor Author

@julieg18 julieg18 left a comment

Choose a reason for hiding this comment

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

Resolved the review comments and going to rerequest reviews since I've changed the PR quite a bit

@codeclimate
Copy link

codeclimate bot commented Aug 9, 2023

Code Climate has analyzed commit dbdd0c9 and detected 0 issues on this pull request.

The test coverage on the diff in this pull request is 96.6% (85% is the threshold).

This pull request will bring the total coverage in the repository to 95.3% (0.0% change).

View more on Code Climate.

@julieg18 julieg18 merged commit e7857d8 into main Aug 9, 2023
3 checks passed
@julieg18 julieg18 deleted the fix-broken-table-on-no-branch branch August 9, 2023 15:41
) {
const nbOfCommitsToShow = this.experiments.getNbOfCommitsToShow(branch)
const branchName = isCurrent ? gitPath.DOT_GIT_HEAD : branch
Copy link
Member

Choose a reason for hiding this comment

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

[F] An explanatory variable would have been good here. The reason being when we come back to this we would have some idea as to why we made this decision. Example would be

  • detachedSafeBranchName
  • safeBranchName

The information won't be lost as we can always come back to this PR (I find the PR via Gitlens file/line history) but you are saving your future self some work by fighting to make the code as expressive as possible 👍🏻.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants