@@ -8,7 +8,7 @@ import type { GitHubOrg, GitHubRepo } from './types';
88
99/**
1010 * Variable for selecting which repositories to monitor.
11- * Dynamically fetches all repos from user's organizations .
11+ * Dynamically fetches repositories the user has access to .
1212 *
1313 * Values are stored as `owner/repo:branch` format.
1414 * If branch is omitted, defaults to `main`.
@@ -24,37 +24,77 @@ export const targetReposVariable: CheckVariable = {
2424 type : 'multi-select' ,
2525 required : true ,
2626 placeholder : 'Select repositories...' ,
27- helpText : 'Select repositories, then specify the branch to check for each .' ,
27+ helpText : 'Select repositories and optionally specify branches (defaults to main) .' ,
2828 fetchOptions : async ( ctx ) => {
29- const orgs = await ctx . fetch < GitHubOrg [ ] > ( '/user/orgs' ) ;
30- const allRepos : Array < { value : string ; label : string } > = [ ] ;
29+ const allRepos = new Map < string , { value : string ; label : string } > ( ) ;
30+ let userReposError : unknown ;
31+ let orgReposError : unknown ;
3132
32- for ( const org of orgs ) {
33+ const addRepo = ( repo : GitHubRepo ) => {
34+ if ( ! repo ?. full_name ) return ;
35+ if ( allRepos . has ( repo . full_name ) ) return ;
36+ allRepos . set ( repo . full_name , {
37+ value : repo . full_name ,
38+ label : `${ repo . full_name } ${ repo . private ? ' (private)' : '' } ` ,
39+ } ) ;
40+ } ;
41+
42+ try {
43+ const allAccessibleRepos = await ctx . fetchAllPages < GitHubRepo > (
44+ '/user/repos?affiliation=owner,collaborator,organization_member&visibility=all' ,
45+ ) ;
46+ const orgRepos = allAccessibleRepos . filter (
47+ ( repo ) => repo . owner ?. type === 'Organization' ,
48+ ) ;
49+ for ( const repo of orgRepos ) {
50+ addRepo ( repo ) ;
51+ }
52+ } catch ( error ) {
53+ userReposError = error ;
54+ }
55+
56+ if ( allRepos . size === 0 ) {
3357 try {
34- const repos = await ctx . fetchAllPages < GitHubRepo > ( `/orgs/${ org . login } /repos` ) ;
35- for ( const repo of repos ) {
36- allRepos . push ( {
37- value : repo . full_name ,
38- label : `${ repo . full_name } ${ repo . private ? ' (private)' : '' } ` ,
39- } ) ;
58+ const orgs = await ctx . fetchAllPages < GitHubOrg > ( '/user/orgs' ) ;
59+ for ( const org of orgs ) {
60+ try {
61+ const repos = await ctx . fetchAllPages < GitHubRepo > ( `/orgs/${ org . login } /repos` ) ;
62+ for ( const repo of repos ) {
63+ addRepo ( repo ) ;
64+ }
65+ } catch ( error ) {
66+ const errorStr = String ( error ) ;
67+ // Skip orgs with SAML SSO that haven't been authorized, or permission errors
68+ // This allows users to still see repos from authorized orgs
69+ if (
70+ errorStr . includes ( '403' ) ||
71+ errorStr . includes ( 'SAML' ) ||
72+ errorStr . includes ( 'Forbidden' )
73+ ) {
74+ console . warn (
75+ `Skipping organization ${ org . login } due to SSO/permission error: ${ errorStr } ` ,
76+ ) ;
77+ continue ;
78+ }
79+ // Re-throw other errors
80+ throw error ;
81+ }
4082 }
4183 } catch ( error ) {
42- const errorStr = String ( error ) ;
43- // Skip orgs with SAML SSO that haven't been authorized, or permission errors
44- // This allows users to still see repos from authorized orgs
45- if (
46- errorStr . includes ( '403' ) ||
47- errorStr . includes ( 'SAML' ) ||
48- errorStr . includes ( 'Forbidden' )
49- ) {
50- continue ;
51- }
52- // Re-throw other errors
53- throw error ;
84+ orgReposError = error ;
85+ }
86+ }
87+
88+ if ( allRepos . size === 0 ) {
89+ if ( userReposError ) {
90+ throw userReposError ;
91+ }
92+ if ( orgReposError ) {
93+ throw orgReposError ;
5494 }
5595 }
5696
57- return allRepos ;
97+ return Array . from ( allRepos . values ( ) ) . sort ( ( a , b ) => a . label . localeCompare ( b . label ) ) ;
5898 } ,
5999} ;
60100
0 commit comments