Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
57b9ca1
Pull client earlier, pass to each command
cheshire137 Oct 11, 2024
dd20108
Rename Client to AzureClient
cheshire137 Oct 11, 2024
c1bb492
Add Client interface
cheshire137 Oct 11, 2024
ef468eb
Add command.Config type
cheshire137 Oct 11, 2024
ec0883b
Docs
cheshire137 Oct 11, 2024
8076365
Add MockClient for testing
cheshire137 Oct 11, 2024
0e91a6e
Add a basic test for the list command
cheshire137 Oct 11, 2024
3122947
Probably don't need XL for lint
cheshire137 Oct 11, 2024
6781863
Add test workflow
cheshire137 Oct 11, 2024
f247ca2
Cancel existing runs when starting a new one
cheshire137 Oct 11, 2024
f1d30e0
Don't need dual push + PR triggers
cheshire137 Oct 11, 2024
644fb0d
Linter fixes
cheshire137 Oct 11, 2024
d236e8f
Add NewConfigWithTerminal
cheshire137 Oct 11, 2024
9a307d6
Fix label for model name in view output
cheshire137 Oct 11, 2024
5d95d27
Add basic test for view command
cheshire137 Oct 11, 2024
13dc795
Return 'not implemented' error by default for mocks
cheshire137 Oct 11, 2024
57b6183
Export ChatChoiceMessage type from azuremodels
cheshire137 Oct 11, 2024
a804f54
Add basic run command test
cheshire137 Oct 11, 2024
bd59113
Don't need to rerun CI if a label changes, for example
cheshire137 Oct 11, 2024
f93fc5e
Run CI when pushing to main branch
cheshire137 Oct 11, 2024
64bd851
Output code coverage percentages
cheshire137 Oct 11, 2024
d69e1ae
Add NewTablePrinter
cheshire137 Oct 11, 2024
3738e1f
Add Config WriteToOut
cheshire137 Oct 11, 2024
099849a
Add runCommandHandler writeToOut
cheshire137 Oct 11, 2024
0c00848
Include client prop on runCommandHandler
cheshire137 Oct 11, 2024
3ede78e
Do we need private module proxy stuff?
cheshire137 Oct 11, 2024
1b48b0f
Don't panic when trying to run commands when not auth'd
cheshire137 Oct 11, 2024
09cd4ae
List param names
cheshire137 Oct 11, 2024
a746559
Merge branch 'main' into add-a-test
cheshire137 Oct 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,27 @@ name: "go-linter"

on:
pull_request:
types: [opened, synchronize, reopened]
Copy link
Member Author

Choose a reason for hiding this comment

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

Run the linter on fewer PR events, such as when the PR is labelled.

merge_group:
workflow_dispatch:
push:
branches:
- 'main'
Copy link
Member Author

Choose a reason for hiding this comment

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

Also lint what gets merged into the main branch.


permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
Copy link
Member Author

Choose a reason for hiding this comment

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

Cancel an existing run of the linter for the same commit.


jobs:
lint:
strategy:
fail-fast: false
runs-on: ubuntu-latest-xl
runs-on: ubuntu-latest
Copy link
Member Author

Choose a reason for hiding this comment

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

Probably don't need the XL version.

env:
GOPROXY: https://goproxy.githubapp.com/mod,https://proxy.golang.org/,direct
GOPROXY: https://proxy.golang.org/,direct
GOPRIVATE: ""
GONOPROXY: ""
GONOSUMDB: github.com/github/*
Expand All @@ -24,9 +32,6 @@ jobs:
go-version: ${{ vars.GOVERSION }}
check-latest: true
- uses: actions/checkout@v4
- name: Configure Go private module access
run: |
echo "machine goproxy.githubapp.com login nobody password ${{ secrets.GOPROXY_TOKEN }}" >> $HOME/.netrc
- name: Lint
# This also does checkout, setup-go, and proxy setup.
uses: github/go-linter@v1.2.1
Expand Down
46 changes: 46 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: "Build and test"

on:
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch:
merge_group:
push:
branches:
- 'main'

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest
env:
GOPROXY: https://proxy.golang.org/,direct
GOPRIVATE: ""
GONOPROXY: ""
GONOSUMDB: github.com/github/*
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ vars.GOVERSION }}
check-latest: true
- name: Verify go.sum is up to date
run: |
go mod tidy
git diff --exit-code go.sum
if [ $? -ne 0 ]; then
echo "Error: go.sum has changed, please run `go mod tidy` and commit the result"
exit 1
fi

- name: Build program
run: go build -v ./...

- name: Run tests
run: go test -race -cover ./...
31 changes: 8 additions & 23 deletions cmd/list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ package list
import (
"fmt"

"github.com/cli/go-gh/v2/pkg/auth"
"github.com/cli/go-gh/v2/pkg/tableprinter"
"github.com/cli/go-gh/v2/pkg/term"
"github.com/github/gh-models/internal/azuremodels"
"github.com/github/gh-models/internal/ux"
"github.com/github/gh-models/pkg/util"
"github.com/github/gh-models/pkg/command"
"github.com/mgutz/ansi"
"github.com/spf13/cobra"
)
Expand All @@ -19,24 +17,14 @@ var (
)

// NewListCommand returns a new command to list available GitHub models.
func NewListCommand() *cobra.Command {
func NewListCommand(cfg *command.Config) *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Short: "List available models",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
terminal := term.FromEnv()
out := terminal.Out()

token, _ := auth.TokenForHost("github.com")
if token == "" {
util.WriteToOut(out, "No GitHub token found. Please run 'gh auth login' to authenticate.\n")
return nil
}

client := azuremodels.NewClient(token)
ctx := cmd.Context()

client := cfg.Client
models, err := client.ListModels(ctx)
if err != nil {
return err
Expand All @@ -47,16 +35,13 @@ func NewListCommand() *cobra.Command {
models = filterToChatModels(models)
ux.SortModels(models)

isTTY := terminal.IsTerminalOutput()

if isTTY {
util.WriteToOut(out, "\n")
util.WriteToOut(out, fmt.Sprintf("Showing %d available chat models\n", len(models)))
util.WriteToOut(out, "\n")
if cfg.IsTerminalOutput {
cfg.WriteToOut("\n")
cfg.WriteToOut(fmt.Sprintf("Showing %d available chat models\n", len(models)))
cfg.WriteToOut("\n")
}

width, _, _ := terminal.Size()
printer := tableprinter.New(out, isTTY, width)
printer := cfg.NewTablePrinter()

printer.AddHeader([]string{"DISPLAY NAME", "MODEL NAME"}, tableprinter.WithColor(lightGrayUnderline))
printer.EndRow()
Expand Down
46 changes: 46 additions & 0 deletions cmd/list/list_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package list

import (
"bytes"
"context"
"testing"

"github.com/github/gh-models/internal/azuremodels"
"github.com/github/gh-models/pkg/command"
"github.com/stretchr/testify/require"
)

func TestList(t *testing.T) {
t.Run("NewListCommand happy path", func(t *testing.T) {
client := azuremodels.NewMockClient()
modelSummary := &azuremodels.ModelSummary{
ID: "test-id-1",
Name: "test-model-1",
FriendlyName: "Test Model 1",
Task: "chat-completion",
Publisher: "OpenAI",
Summary: "This is a test model",
Version: "1.0",
RegistryName: "azure-openai",
}
listModelsCallCount := 0
client.MockListModels = func(ctx context.Context) ([]*azuremodels.ModelSummary, error) {
listModelsCallCount++
return []*azuremodels.ModelSummary{modelSummary}, nil
}
buf := new(bytes.Buffer)
cfg := command.NewConfig(buf, buf, client, true, 80)
listCmd := NewListCommand(cfg)

_, err := listCmd.ExecuteC()

require.NoError(t, err)
require.Equal(t, 1, listModelsCallCount)
output := buf.String()
require.Contains(t, output, "Showing 1 available chat models")
require.Contains(t, output, "DISPLAY NAME")
require.Contains(t, output, "MODEL NAME")
require.Contains(t, output, modelSummary.FriendlyName)
require.Contains(t, output, modelSummary.Name)
})
}
26 changes: 23 additions & 3 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ package cmd
import (
"strings"

"github.com/cli/go-gh/v2/pkg/auth"
"github.com/cli/go-gh/v2/pkg/term"
"github.com/github/gh-models/cmd/list"
"github.com/github/gh-models/cmd/run"
"github.com/github/gh-models/cmd/view"
"github.com/github/gh-models/internal/azuremodels"
"github.com/github/gh-models/pkg/command"
"github.com/github/gh-models/pkg/util"
"github.com/spf13/cobra"
)

Expand All @@ -17,9 +22,24 @@ func NewRootCommand() *cobra.Command {
Short: "GitHub Models extension",
}

cmd.AddCommand(list.NewListCommand())
cmd.AddCommand(run.NewRunCommand())
cmd.AddCommand(view.NewViewCommand())
terminal := term.FromEnv()
out := terminal.Out()
token, _ := auth.TokenForHost("github.com")

var client azuremodels.Client

if token == "" {
Copy link
Collaborator

Choose a reason for hiding this comment

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

For gh models run, previously the code would have immediately bailed out of the command if you had no token set, but now it looks like it's going to try and keep going with a "" token (and eventually run into some 403 error).

I really like that this PR still lets you do some commands without a token, but do you think it's worth trying to preserve the old behavior for run (printing a human-readable error and immediately exiting)?

Copy link
Member Author

@cheshire137 cheshire137 Oct 14, 2024

Choose a reason for hiding this comment

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

do you think it's worth trying to preserve the old behavior for run (printing a human-readable error and immediately exiting)?

So the effect feels the same to users. When I try to run as an unauthenticated user right now on this branch, here's what I get:

% ./gh-models run gpt-4o-mini "hello world"
No GitHub token found. Please run 'gh auth login' to authenticate.
Error: not authenticated
Usage:
  gh models run [model] [prompt] [flags]

Flags:
  -h, --help                   help for run
      --max-tokens string      Limit the maximum tokens for the model response.
      --system-prompt string   Prompt the system.
      --temperature string     Controls randomness in the response, use lower to be more deterministic.
      --top-p string           Controls text diversity by selecting the most probable words until a set probability is reached.

Are you worried about us trying to make an HTTP call with an invalid (blank) token?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't really mind (actually making the HTTP call is not a problem), I was just a little worried that the error would be ugly. Given that it isn't, I have no qualms here - no need to follow up in another branch.

util.WriteToOut(out, "No GitHub token found. Please run 'gh auth login' to authenticate.\n")
client = azuremodels.NewUnauthenticatedClient()
} else {
client = azuremodels.NewAzureClient(token)
}

cfg := command.NewConfigWithTerminal(terminal, client)

cmd.AddCommand(list.NewListCommand(cfg))
cmd.AddCommand(run.NewRunCommand(cfg))
cmd.AddCommand(view.NewViewCommand(cfg))

// Cobra doesn't have a way to specify a two word command (ie. "gh models"), so set a custom usage template
// with `gh`` in it. Cobra will use this template for the root and all child commands.
Expand Down
Loading
Loading