mirror of
https://github.com/go-i2p/go-github-dashboard.git
synced 2025-06-10 02:58:30 -04:00
Add support for repository actions
This commit is contained in:
@ -32,6 +32,7 @@ func NewCache(config *types.Config) *Cache {
|
|||||||
gob.Register([]types.PullRequest{})
|
gob.Register([]types.PullRequest{})
|
||||||
gob.Register([]types.Issue{})
|
gob.Register([]types.Issue{})
|
||||||
gob.Register([]types.Discussion{})
|
gob.Register([]types.Discussion{})
|
||||||
|
gob.Register([]types.WorkflowRun{})
|
||||||
|
|
||||||
cache := &Cache{
|
cache := &Cache{
|
||||||
items: make(map[string]CacheItem),
|
items: make(map[string]CacheItem),
|
||||||
|
@ -221,6 +221,42 @@ func (g *GitHubClient) GetDiscussions(ctx context.Context, owner, repo string) (
|
|||||||
return []types.Discussion{}, nil
|
return []types.Discussion{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetWorkflowRuns fetches recent workflow runs for a repository
|
||||||
|
func (g *GitHubClient) GetWorkflowRuns(ctx context.Context, owner, repo string) ([]types.WorkflowRun, error) {
|
||||||
|
var allRuns []types.WorkflowRun
|
||||||
|
cacheKey := fmt.Sprintf("workflow_runs_%s_%s", owner, repo)
|
||||||
|
|
||||||
|
// Try to get from cache first
|
||||||
|
if cachedRuns, found := g.cache.Get(cacheKey); found {
|
||||||
|
if g.config.Verbose {
|
||||||
|
log.Printf("Using cached workflow runs for %s/%s", owner, repo)
|
||||||
|
}
|
||||||
|
return cachedRuns.([]types.WorkflowRun), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.config.Verbose {
|
||||||
|
log.Printf("Fetching workflow runs for %s/%s", owner, repo)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := &github.ListWorkflowRunsOptions{
|
||||||
|
ListOptions: github.ListOptions{PerPage: 10}, // Limit to 10 most recent runs
|
||||||
|
}
|
||||||
|
|
||||||
|
runs, _, err := g.client.Actions.ListRepositoryWorkflowRuns(ctx, owner, repo, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error fetching workflow runs: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, run := range runs.WorkflowRuns {
|
||||||
|
allRuns = append(allRuns, convertWorkflowRun(run))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache the results
|
||||||
|
g.cache.Set(cacheKey, allRuns)
|
||||||
|
|
||||||
|
return allRuns, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Helper functions to convert GitHub API types to our domain types
|
// Helper functions to convert GitHub API types to our domain types
|
||||||
func convertRepository(repo *github.Repository) types.Repository {
|
func convertRepository(repo *github.Repository) types.Repository {
|
||||||
r := types.Repository{
|
r := types.Repository{
|
||||||
@ -294,3 +330,26 @@ func convertIssue(issue *github.Issue) types.Issue {
|
|||||||
|
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to convert GitHub API types to our domain types
|
||||||
|
func convertWorkflowRun(run *github.WorkflowRun) types.WorkflowRun {
|
||||||
|
workflowRun := types.WorkflowRun{
|
||||||
|
ID: run.GetID(),
|
||||||
|
Name: run.GetName(),
|
||||||
|
URL: run.GetHTMLURL(),
|
||||||
|
Status: run.GetStatus(),
|
||||||
|
Conclusion: run.GetConclusion(),
|
||||||
|
RunNumber: run.GetRunNumber(),
|
||||||
|
Branch: run.GetHeadBranch(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if run.CreatedAt != nil {
|
||||||
|
workflowRun.CreatedAt = run.CreatedAt.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
if run.UpdatedAt != nil {
|
||||||
|
workflowRun.UpdatedAt = run.UpdatedAt.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
return workflowRun
|
||||||
|
}
|
||||||
|
@ -136,10 +136,17 @@ func runGenerate() error {
|
|||||||
log.Printf("Error fetching discussions for %s/%s: %v", owner, repoName, err)
|
log.Printf("Error fetching discussions for %s/%s: %v", owner, repoName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch workflow runs
|
||||||
|
workflowRuns, err := githubClient.GetWorkflowRuns(ctx, owner, repoName)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error fetching workflow runs for %s/%s: %v", owner, repoName, err)
|
||||||
|
}
|
||||||
|
|
||||||
// Update the repository with the fetched data
|
// Update the repository with the fetched data
|
||||||
repo.PullRequests = pullRequests
|
repo.PullRequests = pullRequests
|
||||||
repo.Issues = issues
|
repo.Issues = issues
|
||||||
repo.Discussions = discussions
|
repo.Discussions = discussions
|
||||||
|
repo.WorkflowRuns = workflowRuns
|
||||||
|
|
||||||
// Send the updated repository to the channel
|
// Send the updated repository to the channel
|
||||||
reposChan <- repo
|
reposChan <- repo
|
||||||
|
@ -39,6 +39,7 @@ func NewHTMLGenerator(config *types.Config) (*HTMLGenerator, error) {
|
|||||||
<span>{{.TotalPRs}} open pull requests</span>
|
<span>{{.TotalPRs}} open pull requests</span>
|
||||||
<span>{{.TotalIssues}} open issues</span>
|
<span>{{.TotalIssues}} open issues</span>
|
||||||
<span>{{.TotalDiscussions}} recent discussions</span>
|
<span>{{.TotalDiscussions}} recent discussions</span>
|
||||||
|
<span>{{.TotalWorkflowRuns}} recent workflow runs</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="generated-at">Generated on {{.GeneratedAt.Format "January 2, 2006 at 15:04"}}</p>
|
<p class="generated-at">Generated on {{.GeneratedAt.Format "January 2, 2006 at 15:04"}}</p>
|
||||||
</header>
|
</header>
|
||||||
@ -57,6 +58,7 @@ func NewHTMLGenerator(config *types.Config) (*HTMLGenerator, error) {
|
|||||||
<span class="stat">{{len .PullRequests}} PRs</span>
|
<span class="stat">{{len .PullRequests}} PRs</span>
|
||||||
<span class="stat">{{len .Issues}} issues</span>
|
<span class="stat">{{len .Issues}} issues</span>
|
||||||
<span class="stat">{{len .Discussions}} discussions</span>
|
<span class="stat">{{len .Discussions}} discussions</span>
|
||||||
|
<span class="stat">{{len .WorkflowRuns}} workflows</span>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<div class="collapsible-content">
|
<div class="collapsible-content">
|
||||||
@ -162,6 +164,51 @@ func NewHTMLGenerator(config *types.Config) (*HTMLGenerator, error) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{if .WorkflowRuns}}
|
||||||
|
<div class="collapsible">
|
||||||
|
<input type="checkbox" id="workflows-{{.Name}}" class="toggle">
|
||||||
|
<label for="workflows-{{.Name}}" class="toggle-label section-label workflow-label">
|
||||||
|
Recent Workflow Runs ({{len .WorkflowRuns}})
|
||||||
|
</label>
|
||||||
|
<div class="collapsible-content">
|
||||||
|
<table class="data-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Workflow</th>
|
||||||
|
<th>Branch</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Run #</th>
|
||||||
|
<th>Created</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range .WorkflowRuns}}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{{.URL}}" target="_blank">{{.Name}}</a></td>
|
||||||
|
<td>{{.Branch}}</td>
|
||||||
|
<td class="workflow-status workflow-status-{{.Status}} workflow-conclusion-{{.Conclusion}}">
|
||||||
|
{{if eq .Status "completed"}}
|
||||||
|
{{if eq .Conclusion "success"}}✅ Success{{end}}
|
||||||
|
{{if eq .Conclusion "failure"}}❌ Failure{{end}}
|
||||||
|
{{if eq .Conclusion "cancelled"}}⚪ Cancelled{{end}}
|
||||||
|
{{if eq .Conclusion "skipped"}}⏭️ Skipped{{end}}
|
||||||
|
{{if eq .Conclusion "timed_out"}}⏱️ Timed Out{{end}}
|
||||||
|
{{if eq .Conclusion ""}}⚪ {{.Status}}{{end}}
|
||||||
|
{{else}}
|
||||||
|
{{if eq .Status "in_progress"}}🔄 In Progress{{end}}
|
||||||
|
{{if eq .Status "queued"}}⏳ Queued{{end}}
|
||||||
|
{{if eq .Status ""}}⚪ Unknown{{end}}
|
||||||
|
{{end}}
|
||||||
|
</td>
|
||||||
|
<td>{{.RunNumber}}</td>
|
||||||
|
<td>{{.CreatedAt.Format "2006-01-02 15:04"}}</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
<div class="repo-links">
|
<div class="repo-links">
|
||||||
<a href="repositories/{{.Name}}.md">View as Markdown</a>
|
<a href="repositories/{{.Name}}.md">View as Markdown</a>
|
||||||
@ -433,6 +480,30 @@ footer {
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.workflow-label {
|
||||||
|
color: #2088ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workflow-status {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workflow-status-completed.workflow-conclusion-success {
|
||||||
|
color: #22863a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workflow-status-completed.workflow-conclusion-failure {
|
||||||
|
color: #cb2431;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workflow-status-in_progress {
|
||||||
|
color: #dbab09;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workflow-status-queued {
|
||||||
|
color: #6f42c1;
|
||||||
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
err := os.WriteFile(filepath.Join(g.outputDir, "style.css"), []byte(css), 0644)
|
err := os.WriteFile(filepath.Join(g.outputDir, "style.css"), []byte(css), 0644)
|
||||||
|
@ -59,6 +59,17 @@ func NewMarkdownGenerator(config *types.Config) (*MarkdownGenerator, error) {
|
|||||||
*No recent discussions*
|
*No recent discussions*
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
## Recent Workflow Runs
|
||||||
|
|
||||||
|
{{if .WorkflowRuns}}
|
||||||
|
| Workflow | Branch | Status | Run # | Created |
|
||||||
|
|----------|--------|--------|-------|---------|
|
||||||
|
{{range .WorkflowRuns}}| [{{.Name}}]({{.URL}}) | {{.Branch}} | {{if eq .Status "completed"}}{{if eq .Conclusion "success"}}✅ Success{{end}}{{if eq .Conclusion "failure"}}❌ Failure{{end}}{{if eq .Conclusion "cancelled"}}⚪ Cancelled{{end}}{{if eq .Conclusion "skipped"}}⏭️ Skipped{{end}}{{if eq .Conclusion "timed_out"}}⏱️ Timed Out{{end}}{{if eq .Conclusion ""}}⚪ {{.Status}}{{end}}{{else}}{{if eq .Status "in_progress"}}🔄 In Progress{{end}}{{if eq .Status "queued"}}⏳ Queued{{end}}{{if eq .Status ""}}⚪ Unknown{{end}}{{end}} | {{.RunNumber}} | {{.CreatedAt.Format "2006-01-02 15:04"}} |
|
||||||
|
{{end}}
|
||||||
|
{{else}}
|
||||||
|
*No recent workflow runs*
|
||||||
|
{{end}}
|
||||||
|
|
||||||
---
|
---
|
||||||
*Generated at {{.GeneratedAt.Format "2006-01-02 15:04:05"}}*
|
*Generated at {{.GeneratedAt.Format "2006-01-02 15:04:05"}}*
|
||||||
`)
|
`)
|
||||||
|
@ -16,6 +16,8 @@ type Repository struct {
|
|||||||
PullRequests []PullRequest
|
PullRequests []PullRequest
|
||||||
Issues []Issue
|
Issues []Issue
|
||||||
Discussions []Discussion
|
Discussions []Discussion
|
||||||
|
WorkflowRuns []WorkflowRun
|
||||||
|
TotalWorkflowRuns int
|
||||||
}
|
}
|
||||||
|
|
||||||
// PullRequest represents a GitHub pull request
|
// PullRequest represents a GitHub pull request
|
||||||
@ -69,6 +71,7 @@ type Dashboard struct {
|
|||||||
TotalPRs int
|
TotalPRs int
|
||||||
TotalIssues int
|
TotalIssues int
|
||||||
TotalDiscussions int
|
TotalDiscussions int
|
||||||
|
TotalWorkflowRuns int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config holds the application configuration
|
// Config holds the application configuration
|
||||||
@ -81,3 +84,16 @@ type Config struct {
|
|||||||
CacheTTL time.Duration
|
CacheTTL time.Duration
|
||||||
Verbose bool
|
Verbose bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WorkflowRun represents a GitHub Actions workflow run
|
||||||
|
type WorkflowRun struct {
|
||||||
|
ID int64
|
||||||
|
Name string
|
||||||
|
URL string
|
||||||
|
Status string // "completed", "in_progress", "queued"
|
||||||
|
Conclusion string // "success", "failure", "cancelled", "skipped", etc.
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
RunNumber int
|
||||||
|
Branch string
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user