mirror of
https://github.com/Smaug123/gitea-repo-config
synced 2025-10-05 07:28:40 +00:00
Add refresh-auth (#64)
This commit is contained in:
@@ -149,6 +149,16 @@ module Gitea =
|
||||
Error (Map.ofArray errors)
|
||||
}
|
||||
|
||||
let private createPushMirrorOption (target : Uri) (githubToken : string) : Gitea.CreatePushMirrorOption =
|
||||
let options = Gitea.CreatePushMirrorOption ()
|
||||
options.SyncOnCommit <- Some true
|
||||
options.RemoteAddress <- target.ToString ()
|
||||
options.RemoteUsername <- githubToken
|
||||
options.RemotePassword <- githubToken
|
||||
options.Interval <- "8h0m0s"
|
||||
|
||||
options
|
||||
|
||||
let reconcileDifferingConfiguration
|
||||
(logger : ILogger)
|
||||
(client : IGiteaClient)
|
||||
@@ -369,13 +379,8 @@ module Gitea =
|
||||
| Some token ->
|
||||
async {
|
||||
logger.LogInformation ("Setting up push mirror on {User}:{Repo}", user, repoName)
|
||||
let options = Gitea.CreatePushMirrorOption ()
|
||||
options.SyncOnCommit <- Some true
|
||||
options.RemoteAddress <- (desired.GitHubAddress : Uri).ToString ()
|
||||
options.RemoteUsername <- token
|
||||
options.RemotePassword <- token
|
||||
options.Interval <- "8h0m0s"
|
||||
let! _ = client.RepoAddPushMirror (user, repoName, options) |> Async.AwaitTask
|
||||
let pushMirrorOption = createPushMirrorOption desired.GitHubAddress token
|
||||
let! _ = client.RepoAddPushMirror (user, repoName, pushMirrorOption) |> Async.AwaitTask
|
||||
return ()
|
||||
}
|
||||
| Some desired, Some actual ->
|
||||
@@ -721,3 +726,88 @@ module Gitea =
|
||||
)
|
||||
|> Async.Parallel
|
||||
|> fun a -> async.Bind (a, Array.iter id >> async.Return)
|
||||
|
||||
let toRefresh (client : IGiteaClient) : Async<Map<User, Map<RepoName, Gitea.PushMirror list>>> =
|
||||
async {
|
||||
let! users =
|
||||
Array.getPaginated (fun page limit ->
|
||||
client.AdminGetAllUsers (Some page, Some limit) |> Async.AwaitTask
|
||||
)
|
||||
|
||||
let! results =
|
||||
users
|
||||
|> Seq.map (fun user ->
|
||||
async {
|
||||
let! repos =
|
||||
Array.getPaginated (fun page count ->
|
||||
client.UserListRepos (user.LoginName, Some page, Some count) |> Async.AwaitTask
|
||||
)
|
||||
|
||||
let! pushMirrorResults =
|
||||
repos
|
||||
|> Seq.map (fun r ->
|
||||
async {
|
||||
let! mirrors =
|
||||
Array.getPaginated (fun page count ->
|
||||
Async.AwaitTask (
|
||||
client.RepoListPushMirrors (
|
||||
user.LoginName,
|
||||
r.Name,
|
||||
Some page,
|
||||
Some count
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return RepoName r.Name, mirrors
|
||||
}
|
||||
)
|
||||
|> Async.Parallel
|
||||
|
||||
return User user.LoginName, Map.ofArray pushMirrorResults
|
||||
}
|
||||
)
|
||||
|> Async.Parallel
|
||||
|
||||
return results |> Map.ofArray
|
||||
}
|
||||
|
||||
let refreshAuth
|
||||
(logger : ILogger)
|
||||
(client : IGiteaClient)
|
||||
(githubToken : string)
|
||||
(instructions : Map<User, Map<RepoName, Gitea.PushMirror list>>)
|
||||
: Async<unit>
|
||||
=
|
||||
instructions
|
||||
|> Map.toSeq
|
||||
|> Seq.collect (fun (User user, repos) ->
|
||||
Map.toSeq repos
|
||||
|> Seq.collect (fun (RepoName repoName, mirrors) ->
|
||||
mirrors
|
||||
|> Seq.map (fun mirror ->
|
||||
async {
|
||||
logger.LogInformation (
|
||||
"Refreshing push mirror on {User}:{Repo} to {PushMirrorRemote}",
|
||||
user,
|
||||
repoName,
|
||||
mirror.RemoteAddress
|
||||
)
|
||||
|
||||
let option = createPushMirrorOption (Uri mirror.RemoteAddress) githubToken
|
||||
|
||||
option.Interval <- mirror.Interval
|
||||
option.SyncOnCommit <- mirror.SyncOnCommit
|
||||
|
||||
let! newMirror = Async.AwaitTask (client.RepoAddPushMirror (user, repoName, option))
|
||||
|
||||
let! deleteOldMirror =
|
||||
Async.AwaitTask (client.RepoDeletePushMirror (user, repoName, mirror.RemoteName))
|
||||
|
||||
return ()
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
|> Async.Parallel
|
||||
|> Async.map (Array.iter id)
|
||||
|
@@ -17,6 +17,8 @@ type IGiteaClient =
|
||||
loginName : string * userName : string * page : int64 option * count : int64 option ->
|
||||
Gitea.PushMirror array Task
|
||||
|
||||
abstract RepoDeletePushMirror : user : string * repo : string * remoteName : string -> unit Task
|
||||
|
||||
abstract RepoListBranchProtection : loginName : string * userName : string -> Gitea.BranchProtection array Task
|
||||
abstract RepoDeleteBranchProtection : user : string * repo : string * branch : string -> unit Task
|
||||
|
||||
@@ -57,6 +59,9 @@ module IGiteaClient =
|
||||
member _.RepoListPushMirrors (loginName, userName, page, count) =
|
||||
client.RepoListPushMirrors (loginName, userName, page, count)
|
||||
|
||||
member _.RepoDeletePushMirror (loginName, repo, remoteName) =
|
||||
client.RepoDeletePushMirror (loginName, repo, remoteName)
|
||||
|
||||
member _.RepoListBranchProtection (login, user) =
|
||||
client.RepoListBranchProtection (login, user)
|
||||
|
||||
|
@@ -18,8 +18,10 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="ArgsCrate.fs" />
|
||||
<Compile Include="Result.fs" />
|
||||
<Compile Include="Utils.fs" />
|
||||
<Compile Include="Reconcile.fs" />
|
||||
<Compile Include="OutputSchema.fs" />
|
||||
<Compile Include="RefreshAuth.fs" />
|
||||
<Compile Include="Verify.fs" />
|
||||
<Compile Include="Program.fs" />
|
||||
<None Include="..\README.md" Pack="true" PackagePath="/" />
|
||||
|
@@ -22,6 +22,9 @@ module Program =
|
||||
ArgsCrate.make OutputSchemaArgs.OfParse OutputSchema.run)
|
||||
|
||||
"verify", ("Verify a `reconcile` configuration file", ArgsCrate.make VerifyArgs.OfParse Verify.run)
|
||||
|
||||
"refresh-auth",
|
||||
("Refresh authentication for push mirrors", ArgsCrate.make RefreshAuthArgs.OfParse RefreshAuth.run)
|
||||
|]
|
||||
|> Map.ofArray
|
||||
|
||||
|
@@ -2,10 +2,7 @@ namespace Gitea.Declarative
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open System.Net.Http
|
||||
open Argu
|
||||
open Microsoft.Extensions.Logging.Console
|
||||
open Microsoft.Extensions.Options
|
||||
open Microsoft.Extensions.Logging
|
||||
|
||||
type RunArgsFragment =
|
||||
@@ -61,28 +58,12 @@ module Reconcile =
|
||||
|
||||
let config = GiteaConfig.get args.ConfigFile
|
||||
|
||||
let options =
|
||||
let options = ConsoleLoggerOptions ()
|
||||
|
||||
{ new IOptionsMonitor<ConsoleLoggerOptions> with
|
||||
member _.Get _ = options
|
||||
member _.CurrentValue = options
|
||||
|
||||
member _.OnChange _ =
|
||||
{ new IDisposable with
|
||||
member _.Dispose () = ()
|
||||
}
|
||||
}
|
||||
|
||||
async {
|
||||
use loggerProvider = new ConsoleLoggerProvider (options)
|
||||
use loggerProvider = Utils.createLoggerProvider ()
|
||||
let logger = loggerProvider.CreateLogger "Gitea.Declarative"
|
||||
|
||||
use client = new HttpClient ()
|
||||
client.BaseAddress <- args.GiteaHost
|
||||
client.DefaultRequestHeaders.Add ("Authorization", $"token {args.GiteaAdminApiToken}")
|
||||
|
||||
let client = Gitea.Client client |> IGiteaClient.fromReal
|
||||
use httpClient = Utils.createHttpClient args.GiteaHost args.GiteaAdminApiToken
|
||||
let client = Gitea.Client httpClient |> IGiteaClient.fromReal
|
||||
|
||||
logger.LogInformation "Checking users..."
|
||||
let! userErrors = Gitea.checkUsers config client
|
||||
|
66
Gitea.Declarative/RefreshAuth.fs
Normal file
66
Gitea.Declarative/RefreshAuth.fs
Normal file
@@ -0,0 +1,66 @@
|
||||
namespace Gitea.Declarative
|
||||
|
||||
open System
|
||||
open Argu
|
||||
open Microsoft.Extensions.Logging
|
||||
|
||||
type RefreshAuthArgsFragment =
|
||||
| [<ExactlyOnce ; EqualsAssignmentOrSpaced>] Gitea_Host of string
|
||||
| [<ExactlyOnce ; EqualsAssignmentOrSpaced ; CustomAppSettings "GITEA_ADMIN_API_TOKEN">] Gitea_Admin_Api_Token of
|
||||
string
|
||||
| [<Unique ; EqualsAssignmentOrSpaced ; CustomAppSettings "GITHUB_API_TOKEN">] GitHub_Api_Token of string
|
||||
| Dry_Run
|
||||
|
||||
interface IArgParserTemplate with
|
||||
member s.Usage =
|
||||
match s with
|
||||
| Gitea_Host _ -> "the Gitea host, e.g. https://gitea.mydomain.com"
|
||||
| Gitea_Admin_Api_Token _ ->
|
||||
"a Gitea admin user's API token; can be read from the environment variable GITEA_ADMIN_API_TOKEN"
|
||||
| GitHub_Api_Token _ ->
|
||||
"a GitHub API token with read access to every desired sync-from-GitHub repo; can be read from the environment variable GITHUB_API_TOKEN"
|
||||
| Dry_Run -> "don't actually update the mirrors"
|
||||
|
||||
type RefreshAuthArgs =
|
||||
{
|
||||
GiteaHost : Uri
|
||||
GiteaAdminApiToken : string
|
||||
GitHubApiToken : string
|
||||
DryRun : bool
|
||||
}
|
||||
|
||||
static member OfParse
|
||||
(parsed : ParseResults<RefreshAuthArgsFragment>)
|
||||
: Result<RefreshAuthArgs, ArguParseException>
|
||||
=
|
||||
try
|
||||
{
|
||||
GiteaHost = parsed.GetResult RefreshAuthArgsFragment.Gitea_Host |> Uri
|
||||
GiteaAdminApiToken = parsed.GetResult RefreshAuthArgsFragment.Gitea_Admin_Api_Token
|
||||
GitHubApiToken = parsed.GetResult RefreshAuthArgsFragment.GitHub_Api_Token
|
||||
DryRun = parsed.TryGetResult RefreshAuthArgsFragment.Dry_Run |> Option.isSome
|
||||
}
|
||||
|> Ok
|
||||
with :? ArguParseException as e ->
|
||||
Error e
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module RefreshAuth =
|
||||
|
||||
let run (args : RefreshAuthArgs) : Async<int> =
|
||||
async {
|
||||
use httpClient = Utils.createHttpClient args.GiteaHost args.GiteaAdminApiToken
|
||||
let client = Gitea.Client httpClient |> IGiteaClient.fromReal
|
||||
|
||||
use loggerProvider = Utils.createLoggerProvider ()
|
||||
let logger = loggerProvider.CreateLogger "Gitea.Declarative"
|
||||
|
||||
let! instructions = Gitea.toRefresh client
|
||||
|
||||
if args.DryRun then
|
||||
logger.LogInformation ("Stopping due to --dry-run.")
|
||||
else
|
||||
do! Gitea.refreshAuth logger client args.GitHubApiToken instructions
|
||||
|
||||
return 0
|
||||
}
|
32
Gitea.Declarative/Utils.fs
Normal file
32
Gitea.Declarative/Utils.fs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace Gitea.Declarative
|
||||
|
||||
open System
|
||||
open System.Net.Http
|
||||
open Microsoft.Extensions.Logging.Console
|
||||
open Microsoft.Extensions.Options
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal Utils =
|
||||
|
||||
let createLoggerProvider () =
|
||||
let options =
|
||||
let options = ConsoleLoggerOptions ()
|
||||
|
||||
{ new IOptionsMonitor<ConsoleLoggerOptions> with
|
||||
member _.Get _ = options
|
||||
member _.CurrentValue = options
|
||||
|
||||
member _.OnChange _ =
|
||||
{ new IDisposable with
|
||||
member _.Dispose () = ()
|
||||
}
|
||||
}
|
||||
|
||||
new ConsoleLoggerProvider (options)
|
||||
|
||||
let createHttpClient (host : Uri) (apiKey : string) =
|
||||
let client = new HttpClient ()
|
||||
client.BaseAddress <- host
|
||||
client.DefaultRequestHeaders.Add ("Authorization", $"token {apiKey}")
|
||||
|
||||
client
|
@@ -75,6 +75,8 @@ module Client =
|
||||
|
||||
member _.RepoAddPushMirror (user, repo, createPushMirrorOption) = failwith "Not implemented"
|
||||
|
||||
member _.RepoDeletePushMirror (user, repo, remoteName) = failwith "Not implemented"
|
||||
|
||||
member _.RepoListPushMirrors (loginName, userName, page, count) = failwith "Not implemented"
|
||||
|
||||
member _.RepoListBranchProtection (loginName, userName) = failwith "Not implemented"
|
||||
|
@@ -35,6 +35,7 @@ type GiteaClientMock =
|
||||
UserListRepos : string * int64 option * int64 option -> Gitea.Repository array Task
|
||||
|
||||
RepoAddPushMirror : string * string * Gitea.CreatePushMirrorOption -> Gitea.PushMirror Task
|
||||
RepoDeletePushMirror : string * string * string -> unit Task
|
||||
RepoListPushMirrors : string * string * int64 option * int64 option -> Gitea.PushMirror array Task
|
||||
|
||||
RepoListBranchProtection : string * string -> Gitea.BranchProtection array Task
|
||||
@@ -64,6 +65,7 @@ type GiteaClientMock =
|
||||
UserListRepos = fun _ -> failwith "Unimplemented"
|
||||
|
||||
RepoAddPushMirror = fun _ -> failwith "Unimplemented"
|
||||
RepoDeletePushMirror = fun _ -> failwith "Unimplemented"
|
||||
RepoListPushMirrors = fun _ -> failwith "Unimplemented"
|
||||
|
||||
RepoListBranchProtection = fun _ -> failwith "Unimplemented"
|
||||
@@ -96,6 +98,9 @@ type GiteaClientMock =
|
||||
member this.RepoListPushMirrors (loginName, userName, page, count) =
|
||||
this.RepoListPushMirrors (loginName, userName, page, count)
|
||||
|
||||
member this.RepoDeletePushMirror (loginName, userName, remoteName) =
|
||||
this.RepoDeletePushMirror (loginName, userName, remoteName)
|
||||
|
||||
member this.RepoListBranchProtection (login, user) =
|
||||
this.RepoListBranchProtection (login, user)
|
||||
|
||||
|
Reference in New Issue
Block a user