Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@BagToad
Copy link
Member

@BagToad BagToad commented Nov 18, 2024

Fixes #9760

Requirements

Acceptance Criteria

Given I am in a directory that doesn't have an executable for gh to call as an extension
When I run gh extension install .
Then I get an informative message on stderr saying "An extension has been installed but there is no executable found in this directory, perhaps you need to build it?"

This should be styled when there is a TTY and unstyled when there is not.

When I run gh extension install --help
Then I see an explanation that gh extension install . creates a symlink to an executable in the local directory regardless of whether it exists or not, and it's necessary for the user to build executables out of band if need be.

Demo

image

Reproduction

Error message:

# Setup path to `gh` binary built from this PR
bingh="<PATH_TO_GH_BINARY>"

$bingh ext create testing-9933
cd gh-testing-9933
rm gh-testing-9933
$bingh ext install .

Cleanup/reset:

# Assuming you're still in the testing extension dir...
cd ..
$bingh ext remove gh-testing-9933
rm -rf gh-testing-9933

@BagToad BagToad requested a review from a team as a code owner November 18, 2024 00:47
@BagToad BagToad requested a review from jtmcg November 18, 2024 00:47
@cliAutomation cliAutomation added the external pull request originating outside of the CLI core team label Nov 18, 2024
@BagToad BagToad force-pushed the kw/improve-ext-installation-no-executable-error branch 2 times, most recently from 51e9059 to a34e653 Compare November 18, 2024 03:53
@BagToad BagToad force-pushed the kw/improve-ext-installation-no-executable-error branch from a34e653 to c5497b4 Compare November 18, 2024 04:02
Copy link
Contributor

@jtmcg jtmcg left a comment

Choose a reason for hiding this comment

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

I've tested and it all looks good. I appreciate the updates to the docs language πŸ™Œ I've added some thoughts on how to possibly improve them further.

BagToad and others added 3 commits November 18, 2024 16:21
Better clarify the two extension types in the `extension install` docs.

Co-authored-by: Tyler McGoffin <[email protected]>
@williammartin
Copy link
Member

It occurs to me that this is a breaking change. I wonder if there are scripts out there that do:

gh ext install .
go build ...

Which will start breaking. Need to think about this.

@williammartin
Copy link
Member

So we have two options here:

  1. We just ship this and if someone complains we either say "sorry" and revert it, or say "sorry" and they hopefully make an easy change to their script
  2. We only show this message in interactive mode, which is probably the most common

The advantage of not breaking is clear, the advantage of breaking is consistency. I'd probably favour consistency and if it breaks someone we can apologise. Happy for someone to disagree though.

@BagToad
Copy link
Member Author

BagToad commented Nov 19, 2024

It occurs to me that this is a breaking change. I wonder if there are scripts out there that do:

gh ext install .
go build ...

Which will start breaking. Need to think about this.

@williammartin could you talk more about why this would be breaking? Apologies if it is obvious πŸ˜…

Are you talking about if someone had a script checking if gh ext install . is successful, then it's no longer going to be successful because we're sending a message out on stderr?

Maybe we only send that message to stderr when there is a TTY?

@williammartin
Copy link
Member

@BagToad my bad, I actually thought this was erroring (exit non-zero), not just a warning. I don't feel strongly either way about just the message. Maybe I'd favour just having it on TTY, since realistically, people who are running it in a script probably understand what the semantics are of the command.

@BagToad
Copy link
Member Author

BagToad commented Nov 19, 2024

@williammartin, I think you're right actually. We are returning an error now and that makes us exit non-zero:

! an extension has been installed but there is no executable: expected executable file named "gh-testing-9933" in /Users/kynanware/Documents/orgs/cli/gh-testing-9933, perhaps you need to build it?

❯ echo $?
1

Ideas:

  • Only return the error on TTY, so we only exit non-zero with a TTY.
    • I think this one is a bit confusing - I don't like having a different exit code whether there is a TTY or not.
  • We do not print this message to stderr or return an err like originally written in the A/C. Instead, we print it to stdout when there is a TTY. Exit code remains zero for this case.

@williammartin
Copy link
Member

I think we should continue to exit 0 in all cases. I think most uses of cs.WarningIcon() (which is the icon for !) go to ErrOut. I'd probably be inclined to continue sending it to that stream.

Instead of returning `ErrExtensionExecutableNotFound` error which causes `gh` to have a non-zero exit code, catch it and print the message to stderr, returning nil. Only print the warning to stderr when there is a TTY.
@BagToad BagToad force-pushed the kw/improve-ext-installation-no-executable-error branch from 573283f to e5eedef Compare November 19, 2024 23:42
@BagToad
Copy link
Member Author

BagToad commented Nov 19, 2024

Thanks @williammartin πŸ™‡

I pushed a few commits to fix that if you could give it another review, please.

I also added tests in command_test.go to demonstrate this additional behavior.

Demo

No TTY

❯ $bingh ext install . | cat    

❯ echo $?
0

With TTY

❯ $bingh ext install .          
! an extension has been installed but there is no executable: executable file named "gh-testing-9933" in /Users/kynanware/Documents/orgs/cli/gh-testing-9933 is required to run the extension after install. Perhaps you need to build it?

❯ echo $?
0

Comments:

I saw inconsistency in the way the rest of the codebase checks if we are in a TTY before printing to stderr. I saw three different approaches:

1. Check if stderr is TTY only, then print to stderr:

if opts.IO.IsStderrTTY() {
fmt.Fprintf(opts.IO.ErrOut, "Opening %s in your browser.\n", text.DisplayURL(gistURL))
}

2. Check if stdout is TTY only, then print to stderr:

if io.IsStdoutTTY() {
fmt.Fprintf(io.ErrOut, "Opening %s in your browser.\n", text.DisplayURL(url))
}

3. Check if both stdout and stderr are TTY, then print to stderr:

connectedToTerminal := opts.IO.IsStdoutTTY() && opts.IO.IsStderrTTY() && opts.IO.IsStdinTTY()

if connectedToTerminal {
fmt.Fprintf(stderr, "%s %s %s\n",
cs.Yellow("!"),
cs.Bold(ghrepo.FullName(forkedRepo)),
"already exists")
} else {


With all the different options, I chose option 2 - check if stdout is TTY only, then print to stderr because there is precedent for this already in extension/command.go (see example linked in point 2 above πŸ‘† ). Snippet of what I proposed:

if io.IsStdoutTTY() {
fmt.Fprintln(io.ErrOut, err.Error())
}

Let me know if you think I should have chosen a different option, please.

Copy link
Member

@williammartin williammartin left a comment

Choose a reason for hiding this comment

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

Generally looking really good.

Check for executable file existence using os.IsNotExist for clearer error handling
@williammartin
Copy link
Member

After some discussion we decided that the message should only be displayed when there is a TTY.

Acceptance Criteria

Given I invoke gh without a TTY
And Given I am in a directory that doesn't have an executable for gh to call as an extension
When I run gh extension install .
Then I get no output (as is current behaviour)

~/workspace/cli/bin/gh ext install . | cat

Given I invoke gh with a TTY
And Given I am in a directory that doesn't have an executable for gh to call as an extension
When I run gh extension install .
Then I get an informative message on stderr saying "An extension has been installed but there is no executable found in this directory, perhaps you need to build it?"

➜ ~/workspace/cli/bin/gh ext install .
! an extension has been installed but there is no executable: executable file named "gh-local" in /Users/williammartin/workspace/cli-triaging/local-ext/gh-local is required to run the extension after install. Perhaps you need to build it?

This should be styled when there is a TTY and unstyled when there is not.

When I run gh extension install --help
Then I see an explanation that gh extension install . creates a symlink to an executable in the local directory regardless of whether it exists or not, and it's necessary for the user to build executables out of band if need be.

➜  gh-local ~/workspace/cli/bin/gh  extension install --help
Install a GitHub CLI extension from a GitHub or local repository.

For GitHub repositories, the repository argument can be specified in `OWNER/REPO` format or as a full repository URL.
The URL format is useful when the repository is not hosted on github.com.

For local repositories, often used while developing extensions, use `.` as the
value of the repository argument. Note the following:

- After installing an extension from a locally cloned repository, the GitHub CLI will
manage this extension as a symbolic link (or equivalent mechanism on Windows) pointing
to an executable file with the same name as the repository in the repository's root.
For example, if the repository is named `gh-foobar`, the symbolic link will point
to `gh-foobar` in the extension repository's root.
- When executing the extension, the GitHub CLI will run the executable file found
by following the symbolic link. If no executable file is found, the extension
will fail to execute.
- If the extension is precompiled, the executable file must be built manually and placed
in the repository's root.

For the list of available extensions, see <https://github.com/topics/gh-extension>.

LGTM

@BagToad BagToad enabled auto-merge December 12, 2024 13:58
@BagToad BagToad merged commit e2422b7 into trunk Dec 12, 2024
@BagToad BagToad deleted the kw/improve-ext-installation-no-executable-error branch December 12, 2024 14:08
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Dec 21, 2024
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [cli/cli](https://github.com/cli/cli) | minor | `v2.63.2` -> `v2.64.0` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>cli/cli (cli/cli)</summary>

### [`v2.64.0`](https://github.com/cli/cli/releases/tag/v2.64.0): GitHub CLI 2.64.0

[Compare Source](cli/cli@v2.63.2...v2.64.0)

#### What's Changed

-   docs: improve docs for browse command as of [#&#8203;5352](cli/cli#5352) by [@&#8203;ankddev](https://github.com/ankddev) in cli/cli#10025
-   Open MR against gh-merge-base by [@&#8203;heaths](https://github.com/heaths) in cli/cli#9712
-   Add integration tests for `gh attestation verify` when the `bundle-from-oci` flag is specified by [@&#8203;malancas](https://github.com/malancas) in cli/cli#10020
-   `gh repo rename` help text clarifies new repo name should not include owner by [@&#8203;BagToad](https://github.com/BagToad) in cli/cli#10044
-   fix: list branches in square brackets in `gh run` and `gh codespace` by [@&#8203;uday-rana](https://github.com/uday-rana) in cli/cli#10043
-   Bump actions/attest-build-provenance from 1.4.4 to 2.1.0 by [@&#8203;dependabot](https://github.com/dependabot) in cli/cli#10056
-   Bump golang.org/x/crypto from 0.29.0 to 0.31.0 by [@&#8203;dependabot](https://github.com/dependabot) in cli/cli#10070
-   Improve documentation and error messaging for local extension installations without executables by [@&#8203;BagToad](https://github.com/BagToad) in cli/cli#9933
-   docs: better document auth scopes by [@&#8203;ankddev](https://github.com/ankddev) in cli/cli#10026
-   Sigstore verifier logic updates by [@&#8203;malancas](https://github.com/malancas) in cli/cli#9999
-   `gh pr merge --delete-branch` exits with error when merge requested via merge queue by [@&#8203;BagToad](https://github.com/BagToad) in cli/cli#10074
-   sundry `gh at inspect` improvements by [@&#8203;phillmv](https://github.com/phillmv) in cli/cli#9954
-   Support `pr view` for intra-org forks by [@&#8203;williammartin](https://github.com/williammartin) in cli/cli#10078
-   Print policy information before verifying attestations by [@&#8203;malancas](https://github.com/malancas) in cli/cli#9891
-   Improve error handling in apt setup script by [@&#8203;jobegrabber](https://github.com/jobegrabber) in cli/cli#10055
-   Use Windows compatible file name for downloaded attestations when running `gh attestation download` by [@&#8203;malancas](https://github.com/malancas) in cli/cli#10051
-   Bump github.com/cpuguy83/go-md2man/v2 from 2.0.5 to 2.0.6 by [@&#8203;dependabot](https://github.com/dependabot) in cli/cli#10094
-   Perform all `gh attestation verify` policy options configuration in the `newEnforcementCriteria()` function by [@&#8203;malancas](https://github.com/malancas) in cli/cli#10012

#### New Contributors

-   [@&#8203;ankddev](https://github.com/ankddev) made their first contribution in cli/cli#10025
-   [@&#8203;uday-rana](https://github.com/uday-rana) made their first contribution in cli/cli#10043
-   [@&#8203;jobegrabber](https://github.com/jobegrabber) made their first contribution in cli/cli#10055

**Full Changelog**: cli/cli@v2.63.2...v2.64.0

</details>

---

### Configuration

πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

β™» **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

πŸ”• **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS43Ny4wIiwidXBkYXRlZEluVmVyIjoiMzkuNzcuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90Il19-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external pull request originating outside of the CLI core team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Broken installation of extension in development

5 participants