@@ -81,46 +81,47 @@ func main() {
8181 if verbose {
8282 fmt .Fprintln (os .Stderr , "input:" , pairs )
8383 }
84- result , err := authenticate (ctx )
84+ result , err := authenticate (ctx , pairs [ "username" ] )
8585 if err != nil {
8686 log .Fatalln (err )
8787 }
8888 if verbose {
8989 fmt .Fprintf (os .Stderr , "result: %+v\n " , result )
9090 }
9191 organization := strings .SplitN (pairs ["path" ], "/" , 2 )[0 ]
92+ if organization == "" && ! strings .Contains (pairs ["username" ], "@" ) {
93+ organization = pairs ["username" ]
94+ }
9295 var pt PatToken
96+ if organization == "" {
97+ fmt .Fprintln (os .Stderr , "unable to create personal access token because Azure DevOps organization not specified" )
98+ }
9399 if organization != "" {
94100 pt , err = getPAT (organization , result .AccessToken )
95101 if err != nil {
96- fmt .Fprintln (os .Stderr , "error acquiring Personal Access Token " , err )
102+ fmt .Fprintln (os .Stderr , "error acquiring personal access token " , err )
97103 }
98104 if verbose {
99105 fmt .Fprintf (os .Stderr , "pat: %+v\n " , pt )
100106 }
101107 }
102- var username string
103- if pairs ["username" ] == "" {
104- if organization != "" {
105- username = organization
106- } else {
107- username = "oauth2"
108- }
109- }
110108 output := map [string ]string {}
111- if username != "" {
112- output ["username" ] = username
113- }
114109 var password string
115110 var expiry time.Time
111+ var username string
116112 if pt .Token != "" {
117113 password = pt .Token
118114 expiry = pt .ValidTo
115+ username = organization
119116 } else {
120117 password = result .AccessToken
121118 expiry = result .ExpiresOn
119+ username = result .Account .PreferredUsername
122120 }
123121 output ["password" ] = password
122+ if username != pairs ["username" ] {
123+ output ["username" ] = username
124+ }
124125 if ! expiry .IsZero () {
125126 output ["password_expiry_utc" ] = fmt .Sprintf ("%d" , expiry .UTC ().Unix ())
126127 }
@@ -133,7 +134,7 @@ func main() {
133134 }
134135}
135136
136- func authenticate (ctx context.Context ) (public.AuthResult , error ) {
137+ func authenticate (ctx context.Context , username string ) (public.AuthResult , error ) {
137138 client , err := public .New (
138139 // https://github.com/git-ecosystem/git-credential-manager/blob/8c430c9484c90433ab30c25df7fc1005fe2f4ba4/src/shared/Microsoft.AzureRepos/AzureDevOpsConstants.cs#L15
139140 // magic https://developercommunity.visualstudio.com/t/non-interactive-aad-auth-works-for-visual-studio-a/387853
@@ -146,7 +147,11 @@ func authenticate(ctx context.Context) (public.AuthResult, error) {
146147 }
147148 // https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/manage-personal-access-tokens-via-api?view=azure-devops
148149 scopes := []string {"499b84ac-1321-427f-aa17-267ca6975798/.default" }
149- return client .AcquireTokenInteractive (ctx , scopes )
150+ opts := []public.AcquireInteractiveOption {}
151+ if strings .Contains (username , "@" ) {
152+ opts = append (opts , public .WithLoginHint (username ))
153+ }
154+ return client .AcquireTokenInteractive (ctx , scopes , opts ... )
150155}
151156
152157func getPAT (organization , accessToken string ) (PatToken , error ) {
0 commit comments