44 "context"
55 "fmt"
66 "io"
7+ "net/http"
78 "net/url"
9+ "strconv"
810 "strings"
911 "time"
1012
@@ -19,6 +21,7 @@ import (
1921 "github.com/github/gh-gei/pkg/migration"
2022 awsStorage "github.com/github/gh-gei/pkg/storage/aws"
2123 azureStorage "github.com/github/gh-gei/pkg/storage/azure"
24+ "github.com/github/gh-gei/pkg/storage/ghowned"
2225 "github.com/google/uuid"
2326 "github.com/spf13/cobra"
2427)
@@ -127,6 +130,7 @@ type bbsMigrateRepoArgs struct {
127130 awsRegion string
128131 keepArchive bool
129132 targetAPIURL string
133+ targetUploadsURL string
130134 queueOnly bool
131135 useGithubStorage bool
132136}
@@ -393,7 +397,7 @@ func validateBbsUploadOptions(a *bbsMigrateRepoArgs, envProv bbsMigrateRepoEnvPr
393397 shouldUseAzure := resolveBbsAzureConnectionString (a .azureStorageConnectionString , envProv ) != ""
394398 shouldUseAWS := a .awsBucketName != ""
395399
396- if err := validateBbsUploadConflicts (a , shouldUseAzure , shouldUseAWS , envProv ); err != nil {
400+ if err := validateBbsUploadConflicts (a , shouldUseAzure , shouldUseAWS ); err != nil {
397401 return err
398402 }
399403
@@ -404,8 +408,8 @@ func validateBbsUploadOptions(a *bbsMigrateRepoArgs, envProv bbsMigrateRepoEnvPr
404408 return nil
405409}
406410
407- func validateBbsUploadConflicts (a * bbsMigrateRepoArgs , shouldUseAzure , shouldUseAWS bool , envProv bbsMigrateRepoEnvProvider ) error {
408- if ! shouldUseAWS && hasAWSSubOptions (a , envProv ) {
411+ func validateBbsUploadConflicts (a * bbsMigrateRepoArgs , shouldUseAzure , shouldUseAWS bool ) error {
412+ if ! shouldUseAWS && hasAWSSubOptions (a ) {
409413 return cmdutil .NewUserError ("The AWS S3 bucket name must be provided with --aws-bucket-name if other AWS S3 upload options are set." )
410414 }
411415 if a .useGithubStorage && shouldUseAWS {
@@ -427,11 +431,11 @@ func validateBbsUploadConflicts(a *bbsMigrateRepoArgs, shouldUseAzure, shouldUse
427431 return nil
428432}
429433
430- func hasAWSSubOptions (a * bbsMigrateRepoArgs , envProv bbsMigrateRepoEnvProvider ) bool {
431- return a .awsAccessKey != "" || resolveBbsAWSAccessKey ( "" , envProv ) != "" ||
432- a .awsSecretKey != "" || resolveBbsAWSSecretKey ( "" , envProv ) != "" ||
433- a .awsSessionToken != "" || envProv . AWSSessionToken () != "" ||
434- a .awsRegion != "" || resolveBbsAWSRegion ( "" , envProv ) != ""
434+ func hasAWSSubOptions (a * bbsMigrateRepoArgs ) bool {
435+ return a .awsAccessKey != "" ||
436+ a .awsSecretKey != "" ||
437+ a .awsSessionToken != "" ||
438+ a .awsRegion != ""
435439}
436440
437441func validateBbsAWSCredentials (a * bbsMigrateRepoArgs , envProv bbsMigrateRepoEnvProvider ) error {
@@ -689,8 +693,7 @@ func pollBbsExport(ctx context.Context, bbsAPI bbsMigrateRepoBbsAPI, exportID in
689693 return nil
690694 }
691695
692- if upper != "INITIALISING" && upper != "IN_PROGRESS" { //nolint:misspell // BBS API uses British spelling
693- // Error state
696+ if upper == "FAILED" || upper == "ABORTED" {
694697 return cmdutil .NewUserErrorf ("BBS export failed with state: %s - %s" , exportState , message )
695698 }
696699
@@ -788,6 +791,17 @@ type awsLogAdapter struct {
788791
789792func (a * awsLogAdapter ) LogInfo (format string , args ... interface {}) { a .log .Info (format , args ... ) }
790793
794+ // bbsTokenRoundTripper attaches a Bearer token to every outgoing request.
795+ type bbsTokenRoundTripper struct {
796+ token string
797+ }
798+
799+ func (t * bbsTokenRoundTripper ) RoundTrip (req * http.Request ) (* http.Response , error ) {
800+ req = req .Clone (req .Context ())
801+ req .Header .Set ("Authorization" , "Bearer " + t .token )
802+ return http .DefaultTransport .RoundTrip (req )
803+ }
804+
791805// ---------------------------------------------------------------------------
792806// Production command constructor (used by main.go)
793807// ---------------------------------------------------------------------------
@@ -859,6 +873,7 @@ func newMigrateRepoCmdLive() *cobra.Command {
859873 cmd .Flags ().StringVar (& a .githubPAT , "github-pat" , "" , "Personal access token for the target GitHub instance" )
860874 cmd .Flags ().StringVar (& a .targetRepoVisibility , "target-repo-visibility" , "" , "Target repository visibility (public, private, internal)" )
861875 cmd .Flags ().StringVar (& a .targetAPIURL , "target-api-url" , bbsDefaultTargetAPIURL , "API URL for the target GitHub instance" )
876+ cmd .Flags ().StringVar (& a .targetUploadsURL , "target-uploads-url" , "" , "Uploads URL for the target GitHub instance" )
862877
863878 // Upload storage flags
864879 cmd .Flags ().StringVar (& a .azureStorageConnectionString , "azure-storage-connection-string" , "" , "Azure Blob Storage connection string" )
@@ -873,6 +888,9 @@ func newMigrateRepoCmdLive() *cobra.Command {
873888 cmd .Flags ().BoolVar (& a .queueOnly , "queue-only" , false , "Queue the migration without waiting for completion" )
874889 cmd .Flags ().BoolVar (& a .useGithubStorage , "use-github-storage" , false , "Use GitHub-owned storage for archives" )
875890
891+ // Hidden flags
892+ _ = cmd .Flags ().MarkHidden ("target-uploads-url" )
893+
876894 return cmd
877895}
878896
@@ -970,7 +988,42 @@ func buildBbsArchiveUploader(a *bbsMigrateRepoArgs, envProv bbsMigrateRepoEnvPro
970988 }
971989
972990 if a .useGithubStorage {
973- log .Warning ("GitHub-owned storage is not yet fully implemented in the Go port" )
991+ uploadsURL := a .targetUploadsURL
992+ if uploadsURL == "" {
993+ uploadsURL = "https://uploads.github.com"
994+ }
995+
996+ // Resolve target token for the ghowned HTTP client
997+ targetToken := resolveBbsTargetToken (a .githubPAT , envProv )
998+
999+ ghHTTPClient := & http.Client {
1000+ Transport : & bbsTokenRoundTripper {token : targetToken },
1001+ }
1002+
1003+ var ghOwnedOpts []ghowned.Option
1004+ ghOwnedOpts = append (ghOwnedOpts , ghowned .WithLogger (log ))
1005+
1006+ envReal := env .New ()
1007+ if mebiStr := envReal .GitHubOwnedStorageMultipartMebibytes (); mebiStr != "" {
1008+ if mebi , err := strconv .ParseInt (mebiStr , 10 , 64 ); err == nil {
1009+ ghOwnedOpts = append (ghOwnedOpts , ghowned .WithPartSizeMebibytes (mebi ))
1010+ }
1011+ }
1012+
1013+ ghOwnedClient := ghowned .NewClient (uploadsURL , ghHTTPClient , ghOwnedOpts ... )
1014+
1015+ // Build a GitHub client for org ID resolution
1016+ tgtAPI := a .targetAPIURL
1017+ if tgtAPI == "" {
1018+ tgtAPI = bbsDefaultTargetAPIURL
1019+ }
1020+ targetGH := github .NewClient (targetToken ,
1021+ github .WithAPIURL (tgtAPI ),
1022+ github .WithLogger (log ),
1023+ github .WithVersion (version ),
1024+ )
1025+
1026+ uploaderOpts = append (uploaderOpts , archive .WithGitHub (ghOwnedClient , targetGH ))
9741027 }
9751028
9761029 return archive .NewUploader (uploaderOpts ... ), nil
0 commit comments