Skip to content

Can't install forked extension #9759

Closed

Description

@IvanRibakov

Describe the bug

I have forked an extension and made some improvements. While waiting for the PR to the upstream repo to be reviewed/merged I'd like to share my progress with my colleagues, however I'm unable to install the extension from my fork.

gh version 2.54.0 (2024-08-01)
https://github.com/cli/cli/releases/tag/v2.54.0

Steps to reproduce the behavior

I have tried following commands:

$ gh extensions install IvanRibakov/gh-workflow-stats
$ gh extensions install IvanRibakov/gh-workflow-stats --force
$ gh extensions install IvanRibakov/gh-workflow-stats --force --pin f2286ac

but all of them return the same cryptic error message:

extension is not installable: missing executable

Expected vs actual behavior

Expecting to be able to install an extension from a public fork of a public repo while being able to install the extension from the upstream without issues, instead getting a non-descriptive error.

Logs

Logs

$ GH_DEBUG=api gh extensions install https://github.com/IvanRibakov/gh-workflow-stats --pin f2286ac --force
* Request at 2024-10-15 13:12:09.106395563 +0200 CEST m=+0.050985944
* Request to https://api.github.com/repos/IvanRibakov/gh-workflow-stats/releases/latest
> GET /repos/IvanRibakov/gh-workflow-stats/releases/latest HTTP/1.1
> Host: api.github.com
> Accept: application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview
> Authorization: token ████████████████████
> Content-Type: application/json; charset=utf-8
> Time-Zone: Europe/Madrid
> User-Agent: GitHub CLI 2.54.0
> X-Gh-Cache-Ttl: 30s

⢿< HTTP/2.0 404 Not Found
< Access-Control-Allow-Origin: *
< Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset
< Content-Security-Policy: default-src 'none'
< Content-Type: application/json; charset=utf-8
< Date: Tue, 15 Oct 2024 11:12:14 GMT
< Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
< Server: github.com
< Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
< Vary: Accept-Encoding, Accept, X-Requested-With
< X-Accepted-Oauth-Scopes: repo
< X-Content-Type-Options: nosniff
< X-Frame-Options: deny
< X-Github-Api-Version-Selected: 2022-11-28
< X-Github-Media-Type: github.v3; param=merge-info-preview.nebula-preview; format=json
< X-Github-Request-Id: 9D5A:37C4BC:D9552DD:DCC2930:670E4E0E
< X-Oauth-Scopes: delete:packages, read:org, repo, workflow, write:packages
< X-Ratelimit-Limit: 5000
< X-Ratelimit-Remaining: 4955
< X-Ratelimit-Reset: 1728991844
< X-Ratelimit-Resource: core
< X-Ratelimit-Used: 45
< X-Xss-Protection: 0


{
  "message": "Not Found",
  "documentation_url": "https://docs.github.com/rest/releases/releases#get-the-latest-release",
  "status": "404"
}

* Request took 5.302112651s
* Request at 2024-10-15 13:12:14.408536288 +0200 CEST m=+5.353126669
* Request to https://api.github.com/repos/IvanRibakov/gh-workflow-stats
> GET /repos/IvanRibakov/gh-workflow-stats HTTP/1.1
> Host: api.github.com
> Accept: application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview
> Authorization: token ████████████████████
> Content-Type: application/json; charset=utf-8
> Time-Zone: Europe/Madrid
> User-Agent: GitHub CLI 2.54.0
> X-Gh-Cache-Ttl: 30s

...

{
  ...
  "name": "gh-workflow-stats",
  "full_name": "IvanRibakov/gh-workflow-stats",
  "private": false,
  ...
}

* Request took 254.775396ms
* Request at 2024-10-15 13:12:14.663345618 +0200 CEST m=+5.607935989
* Request to https://api.github.com/repos/IvanRibakov/gh-workflow-stats/contents/gh-workflow-stats
> GET /repos/IvanRibakov/gh-workflow-stats/contents/gh-workflow-stats HTTP/1.1
> Host: api.github.com
> Accept: application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview
> Authorization: token ████████████████████
> Content-Type: application/json; charset=utf-8
> Time-Zone: Europe/Madrid
> User-Agent: GitHub CLI 2.54.0
> X-Gh-Cache-Ttl: 30s

⣾< HTTP/2.0 404 Not Found
< Access-Control-Allow-Origin: *
< Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset
< Content-Security-Policy: default-src 'none'
< Content-Type: application/json; charset=utf-8
< Date: Tue, 15 Oct 2024 11:12:14 GMT
< Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
< Server: github.com
< Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
< Vary: Accept-Encoding, Accept, X-Requested-With
< X-Accepted-Oauth-Scopes: 
< X-Content-Type-Options: nosniff
< X-Frame-Options: deny
< X-Github-Api-Version-Selected: 2022-11-28
< X-Github-Media-Type: github.v3; param=merge-info-preview.nebula-preview; format=json
< X-Github-Request-Id: 9D5A:37C4BC:D95549D:DCC2AE7:670E4E0E
< X-Oauth-Scopes: delete:packages, read:org, repo, workflow, write:packages
< X-Ratelimit-Limit: 5000
< X-Ratelimit-Remaining: 4953
< X-Ratelimit-Reset: 1728991844
< X-Ratelimit-Resource: core
< X-Ratelimit-Used: 47
< X-Xss-Protection: 0

{
  "message": "Not Found",
  "documentation_url": "https://docs.github.com/rest/repos/contents#get-repository-content",
  "status": "404"
}

* Request took 282.202949ms
extension is not installable: missing executable

Activity

  1. IvanRibakov commented on Oct 15, 2024

    @IvanRibakov
    Author

    @williammartin thanks for your help with #9760.

    I think that can almost allow me to close this one as well. Just one question - what exactly must --pin point to?

    The docs say:

    pin extension to a release tag or commit ref

    but clearly it can't be any commit ref since repo is unlikely to contain a commit with the pre-built binary. Is this commit ref simply used to find the release from which to source the binary?

  2. williammartin commented on Oct 15, 2024

    @williammartin
    Member

    Hey @IvanRibakov,

    Thanks for the detailed bug report. I agree that:

    extension is not installable: missing executable

    Is not a very useful error message. Before figuring out what we do next, let me explain how the extension installation works.

    First, we check whether there are installable release artifacts for the given repo and if so, we download the binary and put it in the extension cache. For example, with your upstream extension:

    ➜ gh extension install fchimpan/gh-workflow-stats
    ✓ Installed extension fchimpan/gh-workflow-stats
    
    ➜  ll ~/.local/share/gh/extensions/gh-workflow-stats
    total 17432
    -rwxr-xr-x@ 1 williammartin  staff   8.5M Oct 15 15:45 gh-workflow-stats
    -rw-------@ 1 williammartin  staff   175B Oct 15 15:45 manifest.yml
    
    ➜  cat ~/.local/share/gh/extensions/gh-workflow-stats/manifest.yml
    owner: fchimpan
    name: gh-workflow-stats
    host: github.com
    tag: v0.3.5
    ispinned: false
    path: /Users/williammartin/.local/share/gh/extensions/gh-workflow-stats/gh-workflow-stats
    

    This is known colloquially as a "binary extension".

    If the repo doesn't have a release artifact, then we check whether the given repo contains a script of the same name. If there is a script then we clone the repo into the extension cache. For example:

    ➜ gh ext install andyfeller/gh-kraken
    ⣟Cloning into '/Users/williammartin/.local/share/gh/extensions/gh-kraken'...
    ⢿remote: Enumerating objects: 43, done.
    remote: Counting objects: 100% (43/43), done.
    remote: Compressing objects: 100% (31/31), done.
    remote: Total 43 (delta 17), reused 29 (delta 7), pack-reused 0 (from 0)
    Receiving objects: 100% (43/43), 54.35 KiB | 13.59 MiB/s, done.
    Resolving deltas: 100% (17/17), done.
    ✓ Installed extension andyfeller/gh-kraken
    
    ➜  ll ~/.local/share/gh/extensions/gh-kraken
    total 136
    -rw-r--r--@ 1 williammartin  staff    14B Oct 15 15:49 CODEOWNERS
    -rw-r--r--@ 1 williammartin  staff   5.4K Oct 15 15:49 CODE_OF_CONDUCT.md
    -rw-r--r--@ 1 williammartin  staff   1.1K Oct 15 15:49 LICENSE.txt
    -rw-r--r--@ 1 williammartin  staff   2.4K Oct 15 15:49 README.md
    -rw-r--r--@ 1 williammartin  staff    40K Oct 15 15:49 banner.webp
    -rwxr-xr-x@ 1 williammartin  staff   3.7K Oct 15 15:49 gh-kraken
    

    This is known colloquially as a "script extension".

    In your case, since you forked a binary extension but your repo doesn't have any of the release assets, it falls back to checking whether you have a script and then errors when it doesn't find one.

    As in #9760, you can probably understand that it's a bit out of scope for us to build a binary extension.


    Let me think about what we could do here. Obviously "missing executable" is very unhelpful to start with.

  3. williammartin commented on Oct 15, 2024

    @williammartin
    Member

    I think that can almost allow me to close this one as well. Just one question - what exactly must --pin point to?

    --pin means different things depending on whether it is a binary extension or a script extension. As you call out, pinning to a ref for a binary extension doesn't make sense. However for a script extension, when we clone the repo locally, we will check out that ref and use the script in there. For example:

    ➜  gh ext install andyfeller/gh-kraken --pin dffcf267059aa0fc9882dd8b837c2c3e40d51768
    ⣷Cloning into '/Users/williammartin/.local/share/gh/extensions/gh-kraken'...
    ⡿remote: Enumerating objects: 43, done.
    remote: Counting objects: 100% (43/43), done.
    remote: Compressing objects: 100% (31/31), done.
    remote: Total 43 (delta 17), reused 29 (delta 7), pack-reused 0 (from 0)
    Receiving objects: 100% (43/43), 54.35 KiB | 18.12 MiB/s, done.
    Resolving deltas: 100% (17/17), done.
    ✓ Installed extension andyfeller/gh-kraken
    ✓ Pinned extension at dffcf267059aa0fc9882dd8b837c2c3e40d51768
    
    ➜ cd ~/.local/share/gh/extensions/gh-kraken
    
    ➜ git show | cat
    commit dffcf267059aa0fc9882dd8b837c2c3e40d51768
    
  4. williammartin commented on Oct 15, 2024

    @williammartin
    Member

    I'm using the term "script" colloquially because really it's just checking if there is a file with the given name in the provided repo. Even though the codebase refers to it as script, it could be a binary. It's just that we wouldn't expect binaries to be checked in I suppose.

    In any case, I think we could do with:

    • Updating the help text to explain what install is actually looking for.
    • Updating the missing executable error message, though I'll have to think about whether anyone might be relying on the error message in a script.
  5. IvanRibakov commented on Oct 15, 2024

    @IvanRibakov
    Author

    Thanks for the detailed explanation!

    Let me think about what we could do here. Obviously "missing executable" is very unhelpful to start with.

    It's a pity you had to resort to quoting the source code to explain the extensions mechanism. I have found the Github CLI manual very useful in the past, but it seems that the extensions concept is not as well documented as other (presumably more popular) commands.

    In any case, I think we could do with:

    I think that is spot on!

  6. williammartin commented on Oct 23, 2024

    @williammartin
    Member

    Acceptance Criteria

    When I run gh extension install --help
    Then there is an explanation of how gh looks to install a remote extension.

    See previous comments for details on what that entails.

    Given I have a repo that does not have a release artifact or script that would be acceptable as an extension
    When I run gh extension install <repo>
    Then I get an informative error message along the lines of "extension is not installable: no acceptable release artifact or script found in the "

  7. added
    enhancementa request to improve CLI
    and removed
    bugSomething isn't working
    on Oct 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementa request to improve CLIgh-extensionrelating to the gh extension commandhelp wantedContributions welcome

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions