Skip to content

add context package#17

Merged
mislav merged 24 commits intomasterfrom
ghr-context
Oct 17, 2019
Merged

add context package#17
mislav merged 24 commits intomasterfrom
ghr-context

Conversation

@vilmibm
Copy link
Copy Markdown
Contributor

@vilmibm vilmibm commented Oct 14, 2019

This was an attempt at moving some stuff out of github and into a new package, context. It also houses some code that @probablycorey added in his graphql PR.

It's entirely possible that this isn't the direction we want to go in and I'm open to that. I wanted to open this PR anyway since afaik it doesn't break anything and includes a fair bit of code trimming.

Punted things:

  • config code still lives in github. it was too tightly coupled with github.client, which is still in use in establishing auth context. since @mislav is redoing our auth flow i ultimately just decided to leave this alone after many attempts to cleanly disentangle
  • I wanted to look ahead to more prototype backporting and get rid of localrepo but i didn't get to that
  • I was going to take out github host configuration since we don't really need it right now and are already hardcoding the graphql api endpoint but this was also tightly coupled with github.client

Copy link
Copy Markdown
Contributor

@probablycorey probablycorey left a comment

Choose a reason for hiding this comment

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

I want to use this! I had a few questions about naming and errors.

api/queries.go Outdated
repo := project.Name
currentBranch := currentBranch()
ghRepo, rerr := context.CurrentGitHubRepository()
if rerr != nil {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm guessing that using rerr over err has some benefit here, but I can't tell what it is.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

something that is plaguing me in golang is this scenario:

foo, err := someFunction()
if err != nil { return err }
bar, err := otherFunction() // fails because err is already defined and i'm trying to use := operator

i've been slapping letters onto my err variable names to make them distinct and allow group assignment / initialization. i assume there is a better way to do this and i'm all ears.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Then I have good news for you! You can reuse the err variable with short variable declarations, as long as you declares multiple variables with :=. This code compiles fine!

foo, err := os.Open("file.moo")
if err != nil {
  panic(err)
}
bar, err := os.Open("file.go")
fmt.Printf("%v %v %v", foo, bar, err)

Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original.

via https://golang.org/ref/spec#Short_variable_declarations

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

OH

i didn't even try because i knew := failed for singular assignment

welp, thank you for telling me! i think this PR no longer has the subtly renamed errs but i'll keep it in mind for the future

currentUsername, err := context.CurrentUsername()
if err != nil {
return PullRequestsPayload{}, err
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

To get the branch, repo and username there is a lot of error checking. Would it be simpler to call context.GetContext() that returns a struct with the data and an err?

This would also make it easier to test as well because we could mock what is returned by GetContext()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

👍

}

// GuessRemote attempts to select and return the remote a user likely wants to target when dealing with GitHub repositories.
func GuessRemote() (Remote, error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We pretty much to guess which remote to use, but naming the function that makes it feel more random than it is? Would DefaultRemote work?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

GuessRemote felt honest; DefaultRemote makes it sound like we have some hardcoded default independent of the repo we're in. While not truly random, we are picking a remote without any actual information from the user that it's what they want.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah, I guess I'm trying to pretend we aren't guessing, which doesn't really communicate what it does. So GuessRemote works, GuessDefaultRemote might be more descriptive, but I'm totally fine with GuessRemote now too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

My hope is a name like GuessRemote will motivate us to have a better system for remote determination ^_^

@mislav
Copy link
Copy Markdown
Contributor

mislav commented Oct 17, 2019

💫 Now ready for review! ✨

// Context represents the interface for querying information about the current environment
type Context interface {
	AuthToken() (string, error)
	AuthLogin() (string, error)
	Branch() (string, error)
	SetBranch(string)
	Remotes() (Remotes, error)
	BaseRepo() (*GitHubRepository, error)
	SetBaseRepo(string)
}

// example usage:
branch, err := context.Current().Branch()

Design goals:

  • lazy loading, i.e. individual data is only fetched when requested
  • caching, i.e. data is never re-requested from the filesystem
  • unit-tested code
  • command tests run with their own isolated context
  • ability to override parts of context via --repo, -R and --current-branch, -B global cli flags
  • setting GH_REPO=foo/bar is equivalent to gh --repo foo/bar
  • 🔥 the legacy github package!

@vilmibm To reach the above goals, I had to restructure and rename a lot of the existing context comands. Your code served as a great outline for me, but in the end I mostly rewrote the whole branch. I hope you don't mind! Please let me know what you think 🙇

Breaking:

  • If there isn't a well-formed ~/.config/hub file, the program will panic. We will refine authentication and the initialization of a fresh config file with OAuth authentication flow #6.

@vilmibm vilmibm mentioned this pull request Oct 17, 2019
13 tasks
@mislav
Copy link
Copy Markdown
Contributor

mislav commented Oct 17, 2019

Update:

  • keep original order of git remotes (applies when using remotes.FindByName('*'))
  • avoid crash on malformed yaml config file
  • restructure SSH config parser (used when translating git@... or ssh:// remote URLs), avoid ever reading system or user ~/.ssh/config files in tests
  • more tests!

Copy link
Copy Markdown
Contributor

@mislav mislav left a comment

Choose a reason for hiding this comment

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

@mislav mislav merged commit cb95603 into master Oct 17, 2019
@mislav mislav deleted the ghr-context branch October 17, 2019 15:30
Copy link
Copy Markdown
Contributor

@probablycorey probablycorey left a comment

Choose a reason for hiding this comment

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

This is wonderful, it's going to make the code so much easier to write and maintain! I have a few questions:

  • Is there an advantage to using context.Current() over automatically creating currentContext in the package's Init function? I think we could still mock the context in tests by calling context.InitBlankContext and we could call context.Whaterver() instead of context.Current.Whaterver()

  • The context.BaseRepo was a little confusing to me. It made me think it was contained info about the git repo, and then I was wondering if there are other non-base repos. But if it was called something like GitHubRepo it would have clicked more quickly.

  • AuthLogin makes me thing this method with log me in rather than return the username. Maybe Username or AuthUsername?

P.S. This is my drug 👇

@mislav
Copy link
Copy Markdown
Contributor

mislav commented Oct 17, 2019

  • Is there an advantage to using context.Current() over automatically creating currentContext in the package's Init function?

That's a great question. Right now it doesn't seem like there is a clear advantage, but when designing this, I was trying to be a bit defensive about putting all context methods as being "global" in the context.* scope, and instead made the context an instance that you can obtain a reference to (and swap it around during tests). I've done so that commands could theoretically hold on to their own context instance in the future and that could potentially enable running tests in parallel. If we ran them in parallel now, they would experience race conditions in which one test initializing a mock context could affect the run of another test.

But as things are wired up right now, there's not a clear benefit from calling context.Current().Branch() vs. context.Branch(), except perhaps revealing that there is an underlying context instance which is stateful.

BaseRepo / AuthLogin

This is good feedback around naming. I'll try to rename them according to your suggestions so that their intent is more immediately apparent.

vilmibm pushed a commit that referenced this pull request Jun 29, 2021
fix addArgs and combine by addding branchName parameter
mislav pushed a commit that referenced this pull request Sep 28, 2021
Remove Terminal, no longer needed by ghcs
Stonre pushed a commit to Stonre/strands-fork that referenced this pull request Jul 21, 2025
Add common badges for python projects

Co-authored-by: Mackenzie Zastrow <zastrowm@users.noreply.github.com>
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.

3 participants