Skip to content

Commit ad2458b

Browse files
committed
Initial commit
1 parent 205210f commit ad2458b

19 files changed

Lines changed: 1685 additions & 1 deletion

File tree

.github/workflows/ci.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Set up Go
16+
uses: actions/setup-go@v4
17+
with:
18+
go-version: '1.21'
19+
20+
- name: Download dependencies
21+
run: go mod download
22+
23+
- name: Run tests
24+
run: go test -v ./...
25+
26+
- name: Build
27+
run: go build -v ./cmd/standup
28+
29+
build:
30+
runs-on: ubuntu-latest
31+
needs: test
32+
strategy:
33+
matrix:
34+
goos: [linux, windows, darwin]
35+
goarch: [amd64, arm64]
36+
exclude:
37+
- goarch: arm64
38+
goos: windows
39+
steps:
40+
- uses: actions/checkout@v4
41+
42+
- name: Set up Go
43+
uses: actions/setup-go@v4
44+
with:
45+
go-version: '1.21'
46+
47+
- name: Build binary
48+
env:
49+
GOOS: ${{ matrix.goos }}
50+
GOARCH: ${{ matrix.goarch }}
51+
run: |
52+
mkdir -p dist
53+
go build -o dist/gh-standup-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.goos == 'windows' && '.exe' || '' }} ./cmd/standup
54+
55+
- name: Upload artifacts
56+
uses: actions/upload-artifact@v3
57+
with:
58+
name: gh-standup-${{ matrix.goos }}-${{ matrix.goarch }}
59+
path: dist/

.github/workflows/release.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- name: Set up Go
18+
uses: actions/setup-go@v4
19+
with:
20+
go-version: '1.21'
21+
22+
- name: Build binaries
23+
run: |
24+
mkdir -p dist
25+
26+
# Linux
27+
GOOS=linux GOARCH=amd64 go build -o dist/gh-standup-linux-amd64 ./cmd/standup
28+
GOOS=linux GOARCH=arm64 go build -o dist/gh-standup-linux-arm64 ./cmd/standup
29+
30+
# macOS
31+
GOOS=darwin GOARCH=amd64 go build -o dist/gh-standup-darwin-amd64 ./cmd/standup
32+
GOOS=darwin GOARCH=arm64 go build -o dist/gh-standup-darwin-arm64 ./cmd/standup
33+
34+
# Windows
35+
GOOS=windows GOARCH=amd64 go build -o dist/gh-standup-windows-amd64.exe ./cmd/standup
36+
37+
- name: Create Release
38+
uses: softprops/action-gh-release@v1
39+
with:
40+
files: dist/*
41+
generate_release_notes: true

.gitignore

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Binary
2+
gh-standup
3+
4+
# Go build artifacts
5+
*.exe
6+
*.exe~
7+
*.dll
8+
*.so
9+
*.dylib
10+
*.test
11+
*.out
12+
13+
# Dependency directories
14+
vendor/
15+
16+
# Go workspace file
17+
go.work
18+
19+
# OS specific files
20+
.DS_Store
21+
Thumbs.db
22+
23+
# Editor directories and files
24+
.idea/
25+
.vscode/
26+
*.swp
27+
*.swo
28+
*~

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 gh-standup
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject so the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
.PHONY: build install clean test
2+
3+
# Build the extension
4+
build:
5+
go build -o gh-standup ./cmd/standup
6+
7+
# Install the extension locally for development
8+
install: build
9+
cp gh-standup $(shell gh extension list | grep standup | awk '{print $$3}' || echo ~/.local/share/gh/extensions/gh-standup)/gh-standup
10+
11+
# Clean build artifacts
12+
clean:
13+
rm -f gh-standup
14+
15+
# Run tests
16+
test:
17+
go test ./...
18+
19+
# Install dependencies
20+
deps:
21+
go mod tidy
22+
go mod download
23+
24+
# Run the extension locally
25+
run:
26+
go run ./cmd/standup $(ARGS)

README.md

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,76 @@
1-
# gh-standup
1+
# gh-standup
2+
3+
A GitHub CLI extension that generates AI-powered standup reports using GitHub activity data.
4+
5+
## Installation
6+
7+
### Prerequisites
8+
9+
- [GitHub CLI](https://cli.github.com/) installed and authenticated
10+
- Go 1.21+ (for building from source)
11+
- GitHub token with appropriate permissions (automatically used by GitHub CLI)
12+
13+
### Install from Source
14+
15+
```bash
16+
# Clone the repository
17+
git clone https://github.com/your-username/gh-standup.git
18+
cd gh-standup
19+
20+
# Build and install
21+
make build
22+
gh extension install .
23+
```
24+
25+
### Install from GitHub
26+
27+
```bash
28+
gh extension install your-username/gh-standup
29+
```
30+
31+
## Usage
32+
33+
### Basic Usage
34+
35+
Generate a standup report for yesterday's activity:
36+
37+
```bash
38+
gh standup
39+
```
40+
41+
### Advanced Options
42+
43+
```bash
44+
# Generate report for specific user
45+
gh standup --user octocat
46+
47+
# Generate report for specific repository
48+
gh standup --repo owner/repo
49+
50+
# Look back multiple days
51+
gh standup --days 3
52+
53+
# Use a different AI model
54+
gh standup --model anthropic/claude-3.5-sonnet
55+
56+
# Combine options
57+
gh standup --user octocat --repo microsoft/vscode --days 2 --model openai/gpt-4o
58+
```
59+
60+
## Authentication with Organizations
61+
62+
To ensure the extension can access your organization repositories and activities:
63+
64+
```bash
65+
# Authenticate with GitHub CLI (if not already done)
66+
gh auth login
67+
68+
# Authenticate with your organizations
69+
gh auth refresh -h github.com -s read:org
70+
71+
# To authenticate with a GitHub Enterprise instance
72+
gh auth login --hostname your-enterprise-instance.com
73+
gh auth refresh -h your-enterprise-instance.com -s read:org
74+
```
75+
76+
This ensures your GitHub token includes the necessary organization access permissions.

cmd/standup/main.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"strings"
7+
"time"
8+
9+
"github.com/gh-standup/internal/github"
10+
"github.com/gh-standup/internal/llm"
11+
"github.com/gh-standup/internal/types"
12+
"github.com/spf13/cobra"
13+
)
14+
15+
const extensionName = "standup"
16+
17+
var rootCmd = &cobra.Command{
18+
Use: extensionName,
19+
Short: "Generate AI-powered standup reports",
20+
Long: "A GitHub CLI extension that generates standup reports using GitHub Models and GitHub API data",
21+
RunE: runStandup,
22+
}
23+
24+
var (
25+
flagDays int
26+
flagModel string
27+
flagRepo string
28+
flagUser string
29+
)
30+
31+
func init() {
32+
rootCmd.Flags().IntVarP(&flagDays, "days", "d", 1, "Number of days to look back for activity")
33+
rootCmd.Flags().StringVarP(&flagModel, "model", "m", "openai/gpt-4o", "GitHub Models model to use")
34+
rootCmd.Flags().StringVarP(&flagRepo, "repo", "r", "", "Repository to generate standup for (owner/repo)")
35+
rootCmd.Flags().StringVarP(&flagUser, "user", "u", "", "User to generate standup for (defaults to authenticated user)")
36+
}
37+
38+
func main() {
39+
if err := rootCmd.Execute(); err != nil {
40+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
41+
os.Exit(1)
42+
}
43+
}
44+
45+
func runStandup(cmd *cobra.Command, args []string) error {
46+
githubClient, err := github.NewClient()
47+
if err != nil {
48+
return fmt.Errorf("failed to create GitHub client: %w", err)
49+
}
50+
51+
if flagUser == "" {
52+
fmt.Print("Getting authenticated GitHub user... ")
53+
user, err := githubClient.GetCurrentUser()
54+
if err != nil {
55+
fmt.Println("Failed")
56+
return fmt.Errorf("failed to get current user: %w", err)
57+
}
58+
flagUser = user
59+
fmt.Printf("✅ Found user: %s\n", flagUser)
60+
}
61+
62+
endDate := time.Now()
63+
startDate := endDate.AddDate(0, 0, -flagDays)
64+
65+
fmt.Printf("Analyzing GitHub activity for %s (%s to %s)\n",
66+
flagUser, startDate.Format("2006-01-02"), endDate.Format("2006-01-02"))
67+
68+
fmt.Print("Collecting GitHub activity data...\n")
69+
activities, err := githubClient.CollectActivity(flagUser, flagRepo, startDate, endDate)
70+
if err != nil {
71+
return fmt.Errorf("failed to collect GitHub activity: %w", err)
72+
}
73+
74+
if len(activities) == 0 {
75+
fmt.Println("No GitHub activity found for the specified period.")
76+
return nil
77+
}
78+
79+
fmt.Printf("Found %d activities\n", len(activities))
80+
81+
commits, prs, issues, reviews := countActivities(activities)
82+
fmt.Printf(" %d commits, %d pull requests, %d issues, %d reviews\n", commits, prs, issues, reviews)
83+
84+
llmClient, err := llm.NewClient()
85+
if err != nil {
86+
return fmt.Errorf("failed to create LLM client: %w", err)
87+
}
88+
89+
// Generate standup report using GitHub Models
90+
fmt.Printf("Generating standup report using %s...\n", flagModel)
91+
report, err := llmClient.GenerateStandupReport(activities, flagModel)
92+
if err != nil {
93+
return fmt.Errorf("failed to generate standup report: %w", err)
94+
}
95+
96+
fmt.Println("Report generated successfully!")
97+
fmt.Println("\n" + strings.Repeat("=", 50))
98+
fmt.Println("STANDUP REPORT")
99+
fmt.Println(strings.Repeat("=", 50))
100+
fmt.Println(report)
101+
102+
return nil
103+
}
104+
105+
func countActivities(activities []types.GitHubActivity) (commits, prs, issues, reviews int) {
106+
for _, activity := range activities {
107+
switch activity.Type {
108+
case "commit":
109+
commits++
110+
case "pull_request":
111+
prs++
112+
case "issue":
113+
issues++
114+
case "review":
115+
reviews++
116+
}
117+
}
118+
return
119+
}

0 commit comments

Comments
 (0)