Skip to content
This repository was archived by the owner on Aug 31, 2024. It is now read-only.

Commit 18c41ea

Browse files
committed
Merge branch 'develop'
2 parents 7814786 + bbf6094 commit 18c41ea

File tree

10 files changed

+107
-100
lines changed

10 files changed

+107
-100
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- name: Setup .NET Core
2020
uses: actions/setup-dotnet@v1
2121
with:
22-
dotnet-version: 5.0.100
22+
dotnet-version: 6.0.301
2323

2424
- name: Restore
2525
run: dotnet restore
@@ -58,4 +58,4 @@ jobs:
5858
PATTERN="refs/tags/v"
5959
SUB=""
6060
TAG="${GITHUB_REF/$PATTERN/$SUB}"
61-
docker push $PROJECT/$IMAGE:$TAG
61+
docker push $PROJECT/$IMAGE:$TAG

src/BuildStats/BuildHistoryCharts.fs

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ module BuildChartTypes =
1717

1818
type Build =
1919
{
20-
Id : int
21-
BuildNumber : int
20+
Id : int64
21+
BuildNumber : int64
2222
TimeTaken : TimeSpan
2323
Status : BuildStatus
2424
Branch : string
@@ -99,7 +99,6 @@ module BuildChartHttpClients =
9999
open System.Net.Http.Headers
100100
open Microsoft.Extensions.Caching.Memory
101101
open Microsoft.FSharp.Core.Option
102-
open FSharp.Control.Tasks
103102
open Newtonsoft.Json.Linq
104103
open Giraffe
105104

@@ -133,8 +132,8 @@ module BuildChartHttpClients =
133132
let started = x.Value<Nullable<DateTime>> "started"
134133
let finished = x.Value<Nullable<DateTime>> "finished"
135134
{
136-
Id = x.Value<int> "buildId"
137-
BuildNumber = x.Value<int> "buildNumber"
135+
Id = x.Value<int64> "buildId"
136+
BuildNumber = x.Value<int64> "buildNumber"
138137
Status = x.Value<string> "status" |> parseStatus
139138
Branch = x.Value<string> "branch"
140139
FromPullRequest = x.Value<string> "pullRequestId" |> isPullRequest
@@ -158,13 +157,15 @@ module BuildChartHttpClients =
158157
sprintf "https://ci.appveyor.com/api/projects/%s/%s/history?recordsNumber=%d%s"
159158
account project (5 * buildCount) branchFilter
160159

161-
let request = new HttpRequestMessage(HttpMethod.Get, url)
160+
let requestFactory =
161+
fun _ ->
162+
let request = new HttpRequestMessage(HttpMethod.Get, url)
163+
if authToken.IsSome then
164+
let token = AES.decryptUrlEncodedString Env.cryptoKey authToken.Value
165+
request.Headers.Authorization <- AuthenticationHeaderValue("Bearer", token)
166+
request
162167

163-
if authToken.IsSome then
164-
let token = AES.decryptUrlEncodedString Env.cryptoKey authToken.Value
165-
request.Headers.Authorization <- AuthenticationHeaderValue("Bearer", token)
166-
167-
let! json = httpClient.SendAsync request
168+
let! json = httpClient.SendAsync requestFactory
168169

169170
return json
170171
|> (Str.toOption
@@ -215,8 +216,8 @@ module BuildChartHttpClients =
215216
let finished = x.Value<Nullable<DateTime>> "finished_at"
216217
let state = x.Value<string> "state"
217218
{
218-
Id = x.Value<int> "id"
219-
BuildNumber = x.Value<int> "number"
219+
Id = x.Value<int64> "id"
220+
BuildNumber = x.Value<int64> "number"
220221
Branch = (x.Value<JObject> "branch").Value<string> "name"
221222
FromPullRequest = x.Value<string> "event_type" |> isPullRequest
222223
TimeTaken = BuildStatsHelper.timeTaken started finished
@@ -233,19 +234,13 @@ module BuildChartHttpClients =
233234
task {
234235
let account, project = slug
235236

236-
let request = new HttpRequestMessage()
237-
request.Method <- HttpMethod.Get
238-
request.Headers.Add("Travis-API-Version", "3")
239-
request.Headers.TryAddWithoutValidation("User-Agent", "BuildStats.info-API") |> ignore
240-
241-
let topLevelDomain =
237+
let topLevelDomain, token =
242238
match isFallback, authToken with
243-
| true, _ -> "org"
244-
| false, None -> defaultArg (tryGetTLD account project) "com"
239+
| true, _ -> "org", None
240+
| false, None -> defaultArg (tryGetTLD account project) "com", None
245241
| false, Some t ->
246-
let token = AES.decryptUrlEncodedString Env.cryptoKey t
247-
request.Headers.Authorization <- AuthenticationHeaderValue("token", token)
248-
"com"
242+
let tkn = AES.decryptUrlEncodedString Env.cryptoKey t
243+
"com", Some tkn
249244

250245
let branchFilter =
251246
match branch with
@@ -265,9 +260,20 @@ module BuildChartHttpClients =
265260
branchFilter
266261
eventFilter
267262

268-
request.RequestUri <- Uri(url)
269-
270-
let! json = httpClient.SendAsync request
263+
let requestFactory =
264+
fun _ ->
265+
let request = new HttpRequestMessage()
266+
request.Method <- HttpMethod.Get
267+
request.Headers.Add("Travis-API-Version", "3")
268+
request.Headers.TryAddWithoutValidation("User-Agent", "BuildStats.info-API") |> ignore
269+
request.RequestUri <- Uri(url)
270+
match token with
271+
| None -> ()
272+
| Some t ->
273+
request.Headers.Authorization <- AuthenticationHeaderValue("token", t)
274+
request
275+
276+
let! json = httpClient.SendAsync requestFactory
271277

272278
let builds =
273279
json
@@ -325,8 +331,8 @@ module BuildChartHttpClients =
325331
let started = x.Value<Nullable<DateTime>> "start_time"
326332
let finished = x.Value<Nullable<DateTime>> "stop_time"
327333
{
328-
Id = x.Value<int> "build_num"
329-
BuildNumber = x.Value<int> "build_num"
334+
Id = x.Value<int64> "build_num"
335+
BuildNumber = x.Value<int64> "build_num"
330336
Status = x.Value<string> "status" |> parseStatus
331337
Branch = x.Value<string> "branch"
332338
FromPullRequest = x.Value<string> "subject" |> isPullRequest
@@ -353,8 +359,8 @@ module BuildChartHttpClients =
353359
sprintf "https://circleci.com/api/v1/project/%s/%s%s?limit=%i"
354360
account project branchFilter limit
355361

356-
let request = new HttpRequestMessage(HttpMethod.Get, url)
357-
let! json = httpClient.SendAsync request
362+
let requestFactory = fun _ -> new HttpRequestMessage(HttpMethod.Get, url)
363+
let! json = httpClient.SendAsync requestFactory
358364

359365
return json
360366
|> (Str.toOption
@@ -394,8 +400,8 @@ module BuildChartHttpClients =
394400
let started = x.Value<Nullable<DateTime>> "startTime"
395401
let finished = x.Value<Nullable<DateTime>> "finishTime"
396402
{
397-
Id = x.Value<int> "id"
398-
BuildNumber = x.Value<int> "id"
403+
Id = x.Value<int64> "id"
404+
BuildNumber = x.Value<int64> "id"
399405
Status = x.Value<string> "result" |> parseStatus
400406
Branch = (x.Value<string> "sourceBranch").Replace("refs/heads/", "")
401407
FromPullRequest = x.Value<string> "reason" |> isPullRequest
@@ -421,8 +427,8 @@ module BuildChartHttpClients =
421427
sprintf "https://dev.azure.com/%s/%s/_apis/build/builds?api-version=%s&definitions=%i&$top=%i%s"
422428
account project apiVersion definitionId limit branchFilter
423429

424-
let request = new HttpRequestMessage(HttpMethod.Get, url)
425-
let! json = httpClient.SendAsync request
430+
let requestFactory = fun _ -> new HttpRequestMessage(HttpMethod.Get, url)
431+
let! json = httpClient.SendAsync requestFactory
426432

427433
return json
428434
|> (Str.toOption
@@ -469,8 +475,8 @@ module BuildChartHttpClients =
469475
let outcome = parseStatus status conclusion
470476

471477
{
472-
Id = x.Value<int> "id"
473-
BuildNumber = x.Value<int> "run_number"
478+
Id = x.Value<int64> "id"
479+
BuildNumber = x.Value<int64> "run_number"
474480
Status = outcome
475481
Branch = (x.Value<string> "head_branch")
476482
FromPullRequest = x.Value<string> "event" |> isPullRequest
@@ -497,8 +503,8 @@ module BuildChartHttpClients =
497503
sprintf "https://api.github.com/repos/%s/%s/actions/runs%s"
498504
owner repo branchFilter
499505

500-
let request = new HttpRequestMessage(HttpMethod.Get, url)
501-
let! json = httpClient.SendAsync request
506+
let requestFactory = fun _ -> new HttpRequestMessage(HttpMethod.Get, url)
507+
let! json = httpClient.SendAsync requestFactory
502508

503509
let totalCount, jArray =
504510
Str.toOption json
@@ -517,4 +523,4 @@ module BuildChartHttpClients =
517523
|> convertToBuilds
518524
|> List.filter (BuildStatsHelper.prFilter inclFromPullRequest)
519525
|> List.truncate buildCount
520-
}
526+
}

src/BuildStats/BuildStats.fsproj

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
4-
<TargetFramework>net5.0</TargetFramework>
4+
<TargetFramework>net6.0</TargetFramework>
55
<AssemblyName>BuildStats</AssemblyName>
66
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
77
<EnableDefaultContentItems>false</EnableDefaultContentItems>
88
<RunWorkingDirectory>$(MSBuildThisFileDirectory)</RunWorkingDirectory>
99
</PropertyGroup>
1010

1111
<ItemGroup>
12-
<PackageReference Include="Newtonsoft.Json" Version="12.0.*" />
13-
<PackageReference Include="NUglify" Version="1.11.*" />
14-
<PackageReference Include="Giraffe" Version="5.0.0-rc-6" />
12+
<PackageReference Include="Newtonsoft.Json" Version="13.0.*" />
13+
<PackageReference Include="NUglify" Version="1.20.*" />
14+
<PackageReference Include="Giraffe" Version="6.0.0" />
1515
<PackageReference Include="Logfella" Version="7.1.*" />
16-
<PackageReference Include="Sentry.AspNetCore" Version="2.1.*" />
16+
<PackageReference Include="Sentry.AspNetCore" Version="3.19.*" />
1717
</ItemGroup>
1818

1919
<ItemGroup>
@@ -37,6 +37,7 @@
3737
<Content Include="Assets\*.*">
3838
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
3939
</Content>
40+
<Content Include="Dockerfile" />
4041
</ItemGroup>
4142

42-
</Project>
43+
</Project>

src/BuildStats/Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS build
1+
FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build
22

33
ARG version=0.0.0-undefined
44

@@ -13,7 +13,7 @@ COPY src/BuildStats/. ./
1313
RUN dotnet publish /p:Version=$version -c Release -o published
1414

1515
# Build runtime image
16-
FROM mcr.microsoft.com/dotnet/aspnet:5.0-alpine AS runtime
16+
FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine AS runtime
1717
WORKDIR /app
1818
COPY --from=build /app/published .
19-
ENTRYPOINT ["dotnet", "BuildStats.dll"]
19+
ENTRYPOINT ["dotnet", "BuildStats.dll"]

src/BuildStats/HttpClients.fs

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,24 @@ open System.Net
55
open System.Net.Http
66
open System.Net.Http.Headers
77
open System.Threading.Tasks
8-
open FSharp.Control.Tasks
98
open Logfella
109
open Microsoft.Net.Http.Headers
1110

1211
exception BrokenCircuitException
1312

13+
type HttpRequestFactory = unit -> HttpRequestMessage
14+
1415
type IResilientHttpClient =
15-
abstract member SendAsync : HttpRequestMessage -> Task<HttpResponseMessage>
16+
abstract member SendAsync : HttpRequestFactory -> Task<HttpResponseMessage>
1617

1718
type BaseHttpClient (clientFactory : IHttpClientFactory) =
1819
interface IResilientHttpClient with
19-
member __.SendAsync (request : HttpRequestMessage) =
20+
member __.SendAsync (requestFactory : HttpRequestFactory) =
2021
let userAgent = sprintf "%s/%s" Env.name Env.appVersion
2122
let client = clientFactory.CreateClient()
2223
client.DefaultRequestHeaders.Add("User-Agent", userAgent)
24+
let request = requestFactory()
25+
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue("application/json"))
2326
client.SendAsync request
2427

2528
type CircuitBreakerHttpClient (httpClient : IResilientHttpClient,
@@ -44,23 +47,23 @@ type CircuitBreakerHttpClient (httpClient : IResilientHttpClient,
4447
clientErrorCodes |> List.contains ((int)status)
4548

4649
interface IResilientHttpClient with
47-
member __.SendAsync (request : HttpRequestMessage) =
50+
member __.SendAsync (requestFactory : HttpRequestFactory) =
4851
task {
4952
match isBrokenCircuit with
5053
| true ->
5154
let brokenDuration = DateTime.Now - brokenSince
5255
isBrokenCircuit <- brokenDuration <= minBreakDuration
5356
return raise BrokenCircuitException
5457
| false ->
55-
let! response = httpClient.SendAsync request
58+
let! response = httpClient.SendAsync requestFactory
5659
match response.IsSuccessStatusCode || isClientError response.StatusCode with
5760
| true -> return response
5861
| false ->
5962
let breakDuration = getBreakDuration response
6063
Log.Warning(
6164
sprintf
6265
"Request to '%s' has failed (HTTP status code: %i). Breaking circuit for: %f sec."
63-
(request.RequestUri.ToString())
66+
(response.RequestMessage.RequestUri.ToString())
6467
(int response.StatusCode)
6568
breakDuration.TotalSeconds,
6669
dict [
@@ -83,9 +86,9 @@ type RetryHttpClient (httpClient : IResilientHttpClient,
8386
|| status = HttpStatusCode.ServiceUnavailable
8487
|| status = HttpStatusCode.GatewayTimeout
8588

86-
let rec sendAsync (request : HttpRequestMessage) (retryCount : int) : Task<HttpResponseMessage> =
89+
let rec sendAsync (requestFactory : HttpRequestFactory) (retryCount : int) : Task<HttpResponseMessage> =
8790
task {
88-
let! response = httpClient.SendAsync request
91+
let! response = httpClient.SendAsync requestFactory
8992

9093
match response.IsSuccessStatusCode with
9194
| true -> return response
@@ -97,20 +100,20 @@ type RetryHttpClient (httpClient : IResilientHttpClient,
97100
Log.Warning(
98101
sprintf
99102
"Request to '%s' has failed. The HTTP response status code was: %i. Max retries left: %i. Next wait duration: %f sec."
100-
(request.RequestUri.ToString())
103+
(response.RequestMessage.RequestUri.ToString())
101104
(int response.StatusCode)
102105
retryCount
103106
waitDuration.TotalSeconds,
104107
dict [
105108
"httpClient", "retryClient" :> obj
106109
])
107110
do! Task.Delay waitDuration
108-
return! sendAsync request (retryCount - 1)
111+
return! sendAsync requestFactory (retryCount - 1)
109112
}
110113

111114
interface IResilientHttpClient with
112-
member __.SendAsync (request : HttpRequestMessage) =
113-
sendAsync request maxRetries
115+
member __.SendAsync (requestFactory : HttpRequestFactory) =
116+
sendAsync requestFactory maxRetries
114117

115118
type FallbackHttpClient (httpClient : IResilientHttpClient) =
116119

@@ -121,34 +124,32 @@ type FallbackHttpClient (httpClient : IResilientHttpClient) =
121124
423; 424; 426; 428; 431; 444; 451; 499 ]
122125
clientErrorCodes |> List.contains ((int)status)
123126

124-
member __.SendAsync (request : HttpRequestMessage) =
127+
member __.SendAsync (requestFactory : HttpRequestFactory) =
125128
task {
126129
try
127-
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue("application/json"))
128-
let! response = httpClient.SendAsync request
130+
let! response = httpClient.SendAsync requestFactory
129131
match response.StatusCode with
130132
| HttpStatusCode.OK -> return! response.Content.ReadAsStringAsync()
131133
| _ ->
132134
if isClientError response.StatusCode then
133135
Log.Warning(
134136
sprintf
135137
"Request to '%s' has failed due to a HTTP client error: %i."
136-
(request.RequestUri.ToString())
138+
(response.RequestMessage.RequestUri.ToString())
137139
(int response.StatusCode),
138140
dict [
139141
"httpClient", "fallbackClient" :> obj
140142
])
141143
return ""
142144
with
143145
| :? BrokenCircuitException -> return ""
146+
| :? TaskCanceledException -> return ""
144147
| ex ->
145148
Log.Error(
146-
sprintf
147-
"Exception thrown when sending HTTP request to '%s'."
148-
(request.RequestUri.ToString()),
149+
"Exception thrown when trying to send HTTP request.",
149150
dict [
150151
"httpClient", "fallbackClient" :> obj
151152
],
152153
ex)
153154
return ""
154-
}
155+
}

src/BuildStats/Logging.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ module LoggingExtensions =
7272
| None -> this
7373
| Some dsn ->
7474
this.UseSentry(
75-
fun sentry ->
75+
fun (sentry : Sentry.AspNetCore.SentryAspNetCoreOptions) ->
7676
sentry.Debug <- false
7777
sentry.Environment <- environmentName
7878
sentry.Release <- appVersion
7979
sentry.AttachStacktrace <- true
80-
sentry.Dsn <- dsn)
80+
sentry.Dsn <- dsn)

0 commit comments

Comments
 (0)