@@ -1709,10 +1709,17 @@ type BulkInstallResponse struct {
17091709 SuccessCount int `json:"successCount"`
17101710 FailureCount int `json:"failureCount"`
17111711 OverallSuccess bool `json:"overallSuccess"`
1712+ Channel string `json:"channel,omitempty"`
17121713}
17131714
17141715// BulkInstallPlugins installs multiple plugins from a list of repositories
1716+ // Deprecated: Use BulkInstallPluginsWithChannel instead
17151717func (pi * PluginInstaller ) BulkInstallPlugins (repositories []string ) BulkInstallResponse {
1718+ return pi .BulkInstallPluginsWithChannel (repositories , ReleaseChannelStable )
1719+ }
1720+
1721+ // BulkInstallPluginsWithChannel installs multiple plugins from a list of repositories using the specified channel
1722+ func (pi * PluginInstaller ) BulkInstallPluginsWithChannel (repositories []string , channel ReleaseChannel ) BulkInstallResponse {
17161723 results := make ([]BulkInstallResult , 0 , len (repositories ))
17171724 successCount := 0
17181725 failureCount := 0
@@ -1722,7 +1729,32 @@ func (pi *PluginInstaller) BulkInstallPlugins(repositories []string) BulkInstall
17221729 PluginID : extractPluginIDFromRepo (repo ),
17231730 }
17241731
1725- plugin , err := pi .InstallPlugin (repo )
1732+ // Extract org and repo name from the URL
1733+ parts := strings .Split (repo , "/" )
1734+ var org , repoName string
1735+ for i , part := range parts {
1736+ if part == "github.com" && i + 2 < len (parts ) {
1737+ org = parts [i + 1 ]
1738+ repoName = parts [i + 2 ]
1739+ break
1740+ }
1741+ }
1742+
1743+ if org == "" || repoName == "" {
1744+ // Fallback: use last two parts
1745+ if len (parts ) >= 2 {
1746+ org = parts [len (parts )- 2 ]
1747+ repoName = parts [len (parts )- 1 ]
1748+ }
1749+ }
1750+
1751+ // Remove .git suffix if present
1752+ if strings .HasSuffix (repoName , ".git" ) {
1753+ repoName = repoName [:len (repoName )- 4 ]
1754+ }
1755+
1756+ // Install using the channel-aware method
1757+ plugin , err := pi .InstallFromGitHubWithChannel (org , repoName , channel )
17261758 if err != nil {
17271759 result .Success = false
17281760 result .Error = err .Error ()
@@ -1742,6 +1774,7 @@ func (pi *PluginInstaller) BulkInstallPlugins(repositories []string) BulkInstall
17421774 SuccessCount : successCount ,
17431775 FailureCount : failureCount ,
17441776 OverallSuccess : failureCount == 0 ,
1777+ Channel : string (channel ),
17451778 }
17461779}
17471780
@@ -2003,8 +2036,30 @@ func (pi *PluginInstaller) extractTarGz(reader io.Reader, destDir string) error
20032036 return nil
20042037}
20052038
2039+ // ReleaseChannel represents the type of release to download
2040+ type ReleaseChannel string
2041+
2042+ const (
2043+ // ReleaseChannelStable is for stable releases (tagged versions)
2044+ ReleaseChannelStable ReleaseChannel = "stable"
2045+ // ReleaseChannelBeta is for beta releases (pre-release builds)
2046+ ReleaseChannelBeta ReleaseChannel = "beta"
2047+ // ReleaseChannelSource installs from source code
2048+ ReleaseChannelSource ReleaseChannel = "source"
2049+ )
2050+
20062051// InstallFromGitHubWithBinary installs a plugin, preferring pre-built binaries
2052+ // Deprecated: Use InstallFromGitHubWithChannel instead
20072053func (pi * PluginInstaller ) InstallFromGitHubWithBinary (org string , repo string , useBeta bool ) (PluginMetadata , error ) {
2054+ channel := ReleaseChannelStable
2055+ if useBeta {
2056+ channel = ReleaseChannelBeta
2057+ }
2058+ return pi .InstallFromGitHubWithChannel (org , repo , channel )
2059+ }
2060+
2061+ // InstallFromGitHubWithChannel installs a plugin using the specified release channel
2062+ func (pi * PluginInstaller ) InstallFromGitHubWithChannel (org string , repo string , channel ReleaseChannel ) (PluginMetadata , error ) {
20082063 // Extract plugin ID from repo name
20092064 pluginID := repo
20102065 if strings .HasPrefix (repo , "Plugin_" ) {
@@ -2017,18 +2072,26 @@ func (pi *PluginInstaller) InstallFromGitHubWithBinary(org string, repo string,
20172072 return PluginMetadata {}, fmt .Errorf ("plugin with ID %s already exists" , pluginID )
20182073 }
20192074
2075+ // Source channel always clones from GitHub
2076+ if channel == ReleaseChannelSource {
2077+ return pi .InstallFromGitHub (org , repo , "main" )
2078+ }
2079+
20202080 // Try to download pre-built binary first
2081+ useBeta := channel == ReleaseChannelBeta
20212082 err := pi .downloadPrebuiltBinary (org , repo , pluginID , useBeta )
20222083 if err != nil {
2023- log .Printf ("Pre-built binary not available: %v" , err )
2084+ log .Printf ("Pre-built binary not available for %s channel : %v" , channel , err )
20242085 log .Printf ("Falling back to source installation..." )
20252086
20262087 // Fall back to cloning from GitHub
2027- branch := "main"
2028- if useBeta {
2029- branch = "main" // Beta still uses main branch, just different release
2030- }
2031- return pi .InstallFromGitHub (org , repo , branch )
2088+ return pi .InstallFromGitHub (org , repo , "main" )
2089+ }
2090+
2091+ // Mark plugin as pre-built (no plugin.go file)
2092+ prebuiltMarker := filepath .Join (pluginDir , ".prebuilt" )
2093+ if err := os .WriteFile (prebuiltMarker , []byte (string (channel )), 0644 ); err != nil {
2094+ log .Printf ("Warning: Failed to create prebuilt marker: %v" , err )
20322095 }
20332096
20342097 // Read plugin metadata
0 commit comments