Compare commits

..

7 Commits

Author SHA1 Message Date
agent-company 4e7b072f82 feat: add GetChangedFiles() method to Gitea client for PR file diffs
Add ChangedFile type and GetChangedFiles() method that calls the Gitea
API endpoint GET /repos/{owner}/{repo}/pulls/{index}/files to retrieve
the list of files changed in a pull request. This is a prerequisite for
displaying changed files in the PR detail view (#189).

Includes unit tests for success and error cases.

Closes leeworks-agents/gitea-mobile#205

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 15:06:10 +00:00
AI-Manager baf829349c Merge pull request 'docs: fix SMOKE_TEST.md triage route (/triage -> /)' (#159) from fix/smoke-test-triage-route-157 into master
Build and Push / test (push) Failing after 1m35s
Build and Push / build (push) Has been skipped
2026-03-29 03:04:47 +00:00
agent-company 3145acc423 docs: fix SMOKE_TEST.md triage route reference (/triage -> /)
The triage queue is served at / (the dashboard), not a separate /triage
route. Update Step 7 and the expected results summary table to reference
the correct route, consistent with ROADMAP.md and handlers.go.

Closes leeworks-agents/gitea-mobile#157

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 03:04:07 +00:00
AI-Manager ce3fc36835 Merge pull request 'chore: add go vet step to CI workflow' (#156) from chore/add-go-vet-ci-154 into master
Build and Push / test (push) Failing after 14m51s
Build and Push / build (push) Has been cancelled
2026-03-29 01:03:01 +00:00
agent-company c267bc86a8 chore: add go vet step to CI workflow before tests
Add a `go vet ./...` step that runs before `go test -race ./...` in the
CI pipeline. This catches format string errors, unreachable code, and
other static analysis issues early.

Verified locally: `go vet ./...` exits 0 with no warnings.

Closes leeworks-agents/gitea-mobile#154

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 23:06:43 +00:00
AI-Manager c790a7236c Merge pull request 'chore: improve light mode CSS and document size rationale' (#152) from feature/dark-mode-validation-119 into master
Build and Push / test (push) Failing after 8s
Build and Push / build (push) Has been skipped
2026-03-28 22:03:54 +00:00
agent-company 67973b27aa chore: improve light mode CSS and document file size rationale
- Add accent color overrides for light mode (better contrast on white bg)
- Add light-mode-specific styles for messages, buttons, type badges
- Document why CSS is ~12KB vs the original ~5KB target (all rules active)
- safe-area-inset and tablet breakpoint already verified present

Closes leeworks-agents/gitea-mobile#119

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 21:05:36 +00:00
5 changed files with 146 additions and 5 deletions
+3
View File
@@ -15,6 +15,9 @@ jobs:
with:
go-version: '1.22'
- name: Vet
run: go vet ./...
- name: Run tests
run: go test -race ./...
+3 -3
View File
@@ -73,9 +73,9 @@ curl -s https://gitea-mobile.testing.leeworks.dev | head -5
3. Tap on a PR to see details
4. **Expected**: PR diff summary or review status displays correctly
## Step 7: Core Functionality -- Triage Queue
## Step 7: Core Functionality -- Dashboard / Triage Queue
1. Navigate to the Triage tab (`/triage`)
1. Navigate to the Dashboard/Triage tab (`/`)
2. **Expected**: Unassigned issues and PRs awaiting review appear sorted by priority
## Step 8: Create Issue (Write Operation)
@@ -116,7 +116,7 @@ curl -s https://gitea-mobile.testing.leeworks.dev | head -5
| 4 | Auth | Token saved, API calls work |
| 5 | Issues | List loads, filter works |
| 6 | PRs | List loads with review status |
| 7 | Triage | Queue displays correctly |
| 7 | Dashboard/Triage | Queue displays correctly at `/` |
| 8 | Create issue | Issue created in Gitea |
| 9 | Apply label | Label applied via API |
| 10 | PWA | Standalone mode, safe areas, dark mode |
+27
View File
@@ -760,6 +760,33 @@ func (c *Client) GetPull(ctx context.Context, token, owner, repo string, index i
return &pr, nil
}
// ChangedFile represents a file changed in a pull request.
type ChangedFile struct {
Filename string `json:"filename"`
Status string `json:"status"` // "added", "modified", "removed", "renamed"
Additions int `json:"additions"`
Deletions int `json:"deletions"`
Changes int `json:"changes"`
PreviousFilename string `json:"previous_filename,omitempty"`
}
// GetChangedFiles fetches the list of files changed in a pull request.
func (c *Client) GetChangedFiles(ctx context.Context, token, owner, repo string, index int64) ([]ChangedFile, error) {
path := fmt.Sprintf("/repos/%s/%s/pulls/%d/files?limit=50", owner, repo, index)
resp, err := c.doRequest(ctx, token, http.MethodGet, path, nil)
if err != nil {
return nil, fmt.Errorf("fetching changed files: %w", err)
}
defer resp.Body.Close()
var files []ChangedFile
if err := json.NewDecoder(resp.Body).Decode(&files); err != nil {
return nil, fmt.Errorf("decoding changed files: %w", err)
}
return files, nil
}
// GetIssueComments fetches comments for an issue or pull request.
func (c *Client) GetIssueComments(ctx context.Context, token, owner, repo string, index int64) ([]Comment, error) {
path := fmt.Sprintf("/repos/%s/%s/issues/%d/comments?limit=50", owner, repo, index)
+60
View File
@@ -1456,3 +1456,63 @@ func TestRetryDelay_ExponentialBackoff(t *testing.T) {
}
}
}
func TestGetChangedFiles(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/repos/owner1/repo1/pulls/5/files" {
t.Errorf("unexpected path: %s", r.URL.Path)
}
if r.Header.Get("Authorization") != "token test-token" {
t.Error("missing or wrong Authorization header")
}
files := []ChangedFile{
{Filename: "main.go", Status: "modified", Additions: 10, Deletions: 3, Changes: 13},
{Filename: "new_file.go", Status: "added", Additions: 25, Deletions: 0, Changes: 25},
{Filename: "old_file.go", Status: "removed", Additions: 0, Deletions: 15, Changes: 15},
}
json.NewEncoder(w).Encode(files)
}))
defer server.Close()
c := NewClient(server.URL)
files, err := c.GetChangedFiles(context.Background(), "test-token", "owner1", "repo1", 5)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(files) != 3 {
t.Fatalf("got %d files, want 3", len(files))
}
if files[0].Filename != "main.go" {
t.Errorf("files[0].Filename = %q, want %q", files[0].Filename, "main.go")
}
if files[0].Status != "modified" {
t.Errorf("files[0].Status = %q, want %q", files[0].Status, "modified")
}
if files[1].Status != "added" {
t.Errorf("files[1].Status = %q, want %q", files[1].Status, "added")
}
if files[2].Status != "removed" {
t.Errorf("files[2].Status = %q, want %q", files[2].Status, "removed")
}
}
func TestGetChangedFiles_Error(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
fmt.Fprintln(w, `{"message":"pull request not found"}`)
}))
defer server.Close()
c := NewClient(server.URL)
_, err := c.GetChangedFiles(context.Background(), "test-token", "owner1", "repo1", 999)
if err == nil {
t.Fatal("expected error for 404 response, got nil")
}
if !strings.Contains(err.Error(), "404") {
t.Errorf("error should contain status code 404, got: %v", err)
}
}
+53 -2
View File
@@ -1,4 +1,12 @@
/* Gitea Mobile — Mobile-first CSS (~5KB target) */
/* Gitea Mobile — Mobile-first CSS
* Dark-mode-first: dark colors are the :root defaults.
* Light mode is applied via @media (prefers-color-scheme: light).
*
* Size note: The original ~5KB target was based on the initial Phase 1 scope.
* The CSS has grown to ~12KB as the app added error pages, forms, comments,
* review UI, triage queue, and filter components. All rules are in active use.
* Minification in the Dockerfile build step can reduce transfer size by ~40%.
*/
/* Reset */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
@@ -533,7 +541,7 @@ a:active {
}
}
/* Dark mode is default; light mode override if needed */
/* Dark mode is default; light mode override for prefers-color-scheme: light */
@media (prefers-color-scheme: light) {
:root {
--bg-primary: #ffffff;
@@ -543,6 +551,49 @@ a:active {
--text-primary: #1f2328;
--text-secondary: #656d76;
--text-link: #0969da;
--accent-green: #1a7f37;
--accent-red: #cf222e;
--accent-yellow: #9a6700;
--accent-blue: #0969da;
--accent-purple: #8250df;
}
.message.success {
background: #dafbe1;
border-color: #1a7f37;
}
.message.error {
background: #ffebe9;
border-color: #cf222e;
}
.message.info {
background: #ddf4ff;
border-color: #0969da;
}
.btn-primary {
background: #1a7f37;
}
.btn-primary:active {
background: #116329;
}
.btn-danger {
background: #ffebe9;
border-color: #cf222e;
}
.type-issue {
background: rgba(9, 105, 218, 0.1);
border-color: rgba(9, 105, 218, 0.3);
}
.type-pull {
background: rgba(26, 127, 55, 0.1);
border-color: rgba(26, 127, 55, 0.3);
}
}