Skip to content

Commit 62b3c69

Browse files
committed
better azure pipelines integration and building docker image
1 parent 8b14e84 commit 62b3c69

17 files changed

+158
-29
lines changed

.dockerignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.vs/
2+
.vscode/
3+
_ReSharper.*/

CompatBot/CompatBot.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<UserSecretsId>c2e6548b-b215-4a18-a010-958ef294b310</UserSecretsId>
99
<LangVersion>latest</LangVersion>
1010
<NoWarn>1701;1702;VSTHRD200</NoWarn>
11+
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
1112
</PropertyGroup>
1213

1314
<ItemGroup>
@@ -37,6 +38,7 @@
3738
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.2.0" />
3839
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.2.4" />
3940
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="2.2.0" />
41+
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.4.10" />
4042
<PackageReference Include="Nerdbank.Streams" Version="2.3.26" />
4143
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
4244
<PackageReference Include="NLog" Version="4.6.6" />

CompatBot/Config.cs

+8-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.IO;
66
using System.Reflection;
77
using System.Threading;
8+
using CompatBot.Utils;
89
using DSharpPlus.Entities;
910
using Microsoft.Extensions.Configuration;
1011
using Microsoft.Extensions.Configuration.UserSecrets;
@@ -54,20 +55,24 @@ internal static class Config
5455
public static int MinimumPiracyTriggerLength => config.GetValue(nameof(MinimumPiracyTriggerLength), 4);
5556

5657
public static string Token => config.GetValue(nameof(Token), "");
57-
public static string LogPath => config.GetValue(nameof(LogPath), "logs/bot.log"); // paths are relative to the assembly, so this will put it in the project's root
58+
public static string LogPath => config.GetValue(nameof(LogPath), "../../../logs/"); // paths are relative to the assembly, so this will put it in the project's root
5859
public static string IrdCachePath => config.GetValue(nameof(IrdCachePath), "./ird/");
5960

6061
public static string GoogleApiConfigPath
6162
{
6263
get
6364
{
65+
if (SandboxDetector.Detect() == "Docker")
66+
return "/bot-config/credentials.json";
67+
6468
if (Assembly.GetEntryAssembly().GetCustomAttribute<UserSecretsIdAttribute>() is UserSecretsIdAttribute attribute)
6569
{
6670
var path = Path.GetDirectoryName(PathHelper.GetSecretsPathFromSecretsId(attribute.UserSecretsId));
6771
path = Path.Combine(path, "credentials.json");
6872
if (File.Exists(path))
6973
return path;
7074
}
75+
7176
return "Properties/credentials.json";
7277
}
7378
}
@@ -154,7 +159,7 @@ static Config()
154159

155160
config = new ConfigurationBuilder()
156161
.AddUserSecrets(Assembly.GetExecutingAssembly()) // lower priority
157-
//.AddEnvironmentVariables()
162+
.AddEnvironmentVariables()
158163
.AddInMemoryCollection(inMemorySettings) // higher priority
159164
.Build();
160165
Log = GetLog();
@@ -172,7 +177,7 @@ private static ILogger GetLog()
172177
{
173178
var config = new NLog.Config.LoggingConfiguration();
174179
var fileTarget = new FileTarget("logfile") {
175-
FileName = Path.Combine("../../../", LogPath),
180+
FileName = Path.Combine(LogPath, "bot.log"),
176181
ArchiveEvery = FileArchivePeriod.Day,
177182
ArchiveNumbering = ArchiveNumberingMode.DateAndSequence,
178183
KeepFileOpen = true,

CompatBot/Database/DbImporter.cs

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Threading;
44
using System.Threading.Tasks;
55
using CompatBot.Database.Migrations;
6+
using CompatBot.Utils;
67
using Microsoft.Data.Sqlite;
78
using Microsoft.EntityFrameworkCore;
89
using Microsoft.EntityFrameworkCore.Migrations.Internal;
@@ -110,6 +111,9 @@ await db.ExecuteSqlCommandAsync(@"CREATE TABLE `temp_new_explanation` (
110111

111112
internal static string GetDbPath(string dbName, Environment.SpecialFolder desiredFolder)
112113
{
114+
if (SandboxDetector.Detect() == "Docker")
115+
return Path.Combine("/bot-db/", dbName);
116+
113117
var settingsFolder = Path.Combine(Environment.GetFolderPath(desiredFolder), "compat-bot");
114118
try
115119
{

CompatBot/Program.cs

+14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.IO;
3+
using System.Reflection;
34
using System.Threading;
45
using System.Threading.Tasks;
56
using CompatBot.Commands;
@@ -8,10 +9,12 @@
89
using CompatBot.Database.Providers;
910
using CompatBot.EventHandlers;
1011
using CompatBot.ThumbScrapper;
12+
using CompatBot.Utils;
1113
using DSharpPlus;
1214
using DSharpPlus.CommandsNext;
1315
using DSharpPlus.Entities;
1416
using DSharpPlus.Interactivity;
17+
using Microsoft.Extensions.Configuration.UserSecrets;
1518
using Microsoft.Extensions.DependencyInjection;
1619

1720
namespace CompatBot
@@ -24,6 +27,17 @@ internal static class Program
2427

2528
internal static async Task Main(string[] args)
2629
{
30+
if (args.Length > 0 && args[0] == "--dry-run")
31+
{
32+
Console.WriteLine("Confinement: " + SandboxDetector.Detect());
33+
Console.WriteLine("Database path: " + Path.GetDirectoryName(Path.GetFullPath(DbImporter.GetDbPath("fake.db", Environment.SpecialFolder.ApplicationData))));
34+
if (Assembly.GetEntryAssembly().GetCustomAttribute<UserSecretsIdAttribute>() is UserSecretsIdAttribute attribute)
35+
{
36+
Console.WriteLine("Bot config path: " + Path.GetDirectoryName(Path.GetFullPath(Config.GoogleApiConfigPath)));
37+
}
38+
return;
39+
}
40+
2741
var singleInstanceCheckThread = new Thread(() =>
2842
{
2943
using (var instanceLock = new Mutex(false, @"Global\RPCS3 Compatibility Bot"))

CompatBot/Properties/launchSettings.json

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
"profiles": {
33
"default": {
44
"commandName": "Project"
5+
},
6+
"Docker": {
7+
"commandName": "Docker"
58
}
69
}
710
}

CompatBot/Utils/Extensions/StringUtils.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ public static string StrikeThrough(this string str)
218218
return result.ToString(0, result.Length-1);
219219
}
220220

221-
public static string GetMoons(decimal? stars)
221+
public static string GetMoons(decimal? stars, bool haveFun = true)
222222
{
223223
if (!stars.HasValue)
224224
return null;
@@ -232,7 +232,7 @@ public static string GetMoons(decimal? stars)
232232

233233
if (halfStar == 4)
234234
{
235-
if (new Random().Next(100) == 69)
235+
if (haveFun && new Random().Next(100) == 69)
236236
result += "🌝";
237237
else
238238
result += "🌕";
@@ -246,7 +246,7 @@ public static string GetMoons(decimal? stars)
246246

247247
for (var i = 0; i < noStars; i++)
248248
{
249-
if (i == 0 && halfStar == 0 && new Random().Next(100) == 69)
249+
if (haveFun && i == 0 && halfStar == 0 && new Random().Next(100) == 69)
250250
result += "🌚";
251251
else
252252
result += "🌑";

CompatBot/Utils/SandboxDetector.cs

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ public static string Detect()
1212
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("FLATPAK_SYSTEM_DIR")))
1313
return "Flatpak";
1414

15+
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("RUNNING_IN_DOCKER")))
16+
return "Docker";
17+
1518
return null;
1619
}
1720
}

CompatBot/Utils/TimeParser.cs

+2
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,7 @@ public static DateTime Normalize(this DateTime date)
8282
return date.ToUniversalTime();
8383
return date.AsUtc();
8484
}
85+
86+
public static List<string> GetSupportedTimeZoneAbbreviations() => TimeZoneMap.Keys.ToList();
8587
}
8688
}

Dockerfile

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM mcr.microsoft.com/dotnet/core/sdk:latest AS base
2+
COPY packages /root/.nuget/packages/
3+
WORKDIR /src
4+
COPY . .
5+
RUN rm -rf ./packages
6+
RUN git status
7+
RUN dotnet build "CompatBot/CompatBot.csproj" -c Release
8+
ENV RUNNING_IN_DOCKER true
9+
WORKDIR /src/CompatBot
10+
RUN dotnet run -c Release --dry-run
11+
ENTRYPOINT ["dotnet", "run", "-c Release", "CompatBot.csproj"]

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,20 @@ How to Build
4747

4848
How to Run in Production
4949
------------------------
50+
51+
### Running from source
5052
* Change configuration if needed (probably just token):
5153
* use `$ dotnet user-secrets set Token <your_token_here>`
5254
* for available configuration variables, see [Config.cs](CompatBot/Config.cs#L31)
5355
* Put `bot.db` in `CompatBot/` if you have one
5456
* `$ cd CompatBot`
5557
* `$ dotnet run -c Release`
5658

59+
### Running with Docker
60+
* Official image is hosted on [Docker Hub](https://hub.docker.com/r/13xforever/rpcs3-discord-bot).
61+
* You should pull images tagged with `release-latest` (same thing as `latest`)
62+
* Please take a look at the [docker-compose.yml](docker-compose.yml) for required configuration (bot token and mounting points for persistent data).
63+
5764
External resources that need manual updates
5865
-------------------------------------------
5966
* [Unicode confusables](http://www.unicode.org/Public/security/latest/confusables.txt) gzipped, for Homoglyph checks

Tests/IrdTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Tests
66
{
7-
[TestFixture]
7+
[TestFixture, Explicit("Requires files to run")]
88
public class IrdTests
99
{
1010
[Test]

Tests/StarsFormatTest.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class StarsFormatTest
2323
[TestCase(1.0, "🌕🌑🌑🌑🌑")]
2424
public void FormatTest(decimal score, string expectedValue)
2525
{
26-
Assert.That(StringUtils.GetMoons(score), Is.EqualTo(expectedValue), "Failed for " + score);
26+
Assert.That(StringUtils.GetMoons(score, false), Is.EqualTo(expectedValue), "Failed for " + score);
2727
}
2828
}
2929
}

Tests/TimeParserTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ namespace Tests
88
public class TimeParserTests
99
{
1010
[TestCase("2019-8-19 6:00 PT", "2019-08-19T13:00Z")]
11-
[TestCase("2019-8-19 17:00 bst", "2019-08-19T16:00Z")]
11+
[TestCase("2019-8-19 17:00 cest", "2019-08-19T15:00Z")]
1212
[TestCase("2019-9-1 22:00 jst", "2019-09-01T13:00Z")]
1313
public void TimeZoneConverterTest(string input, string utcInput)
1414
{
1515
var utc = DateTime.Parse(utcInput).Normalize();
16-
Assert.That(TimeParser.TryParse(input, out var result), Is.True);
16+
Assert.That(TimeParser.TryParse(input, out var result), Is.True, $"{input} failed to parse\nSupported time zones: {string.Join(", ", TimeParser.GetSupportedTimeZoneAbbreviations())}");
1717
Assert.That(result, Is.EqualTo(utc));
1818
Assert.That(result.Kind, Is.EqualTo(DateTimeKind.Utc));
1919
}

azure-pipelines.yml

+70-15
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,75 @@
1-
# ASP.NET Core
2-
# Build and test ASP.NET Core projects targeting .NET Core.
3-
# Add steps that run tests, create a NuGet package, deploy, and more:
4-
# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core
1+
jobs:
2+
- job: BuildAndTest
3+
displayName: 'Run tests'
4+
pool:
5+
vmImage: 'ubuntu-latest'
6+
steps:
7+
- script: dotnet restore --ignore-failed-sources
8+
displayName: 'dotnet restore (first try)'
59

6-
pool:
7-
vmImage: 'Ubuntu 16.04'
10+
- script: dotnet restore --ignore-failed-sources
11+
displayName: 'dotnet restore (second try)'
812

9-
variables:
10-
buildConfiguration: 'Release'
13+
- script: dotnet restore
14+
displayName: 'dotnet restore (last try)'
1115

12-
steps:
13-
- script: dotnet restore
14-
displayName: 'dotnet restore'
16+
- script: dotnet build --configuration Debug
17+
displayName: 'dotnet build Debug'
1518

16-
- script: dotnet build --configuration Debug
17-
displayName: 'dotnet build Debug'
19+
- task: DotNetCoreCLI@2
20+
displayName: 'dotnet test'
21+
inputs:
22+
command: 'test'
23+
projects: Tests/Tests.csproj
1824

19-
- script: dotnet build --configuration Release
20-
displayName: 'dotnet build Release'
25+
- job: DockerImage
26+
displayName: 'Build Docker image'
27+
condition: and(and(succeeded(), eq(variables['ReleaseBranch'], variables['Build.SourceBranch'])), ne(format('{0}', variables['DockerConnection']), ''))
28+
dependsOn: BuildAndTest
29+
pool:
30+
vmImage: 'ubuntu-latest'
31+
steps:
32+
- script: git checkout -f $(Build.SourceBranchName)
33+
displayName: 'create local tracking branch'
34+
35+
- script: git clean -dfx
36+
displayName: 'clean build artifacts'
37+
38+
- script: dotnet restore --ignore-failed-sources
39+
displayName: 'dotnet restore (first try)'
40+
41+
- script: dotnet restore --ignore-failed-sources
42+
displayName: 'dotnet restore (second try)'
43+
44+
- script: dotnet restore
45+
displayName: 'dotnet restore (last try)'
46+
47+
- script: dotnet build --configuration Release
48+
displayName: 'dotnet build Release'
49+
50+
- script: mkdir packages && cp -a /home/vsts/.nuget/packages ./packages/
51+
displayName: 'copy nuget package cache for docker'
52+
53+
- task: Docker@2
54+
displayName: 'building release docker image'
55+
condition: and(succeeded(), eq(variables['ReleaseKind'], 'release'))
56+
inputs:
57+
containerRegistry: $(DockerConnection)
58+
repository: $(DockerRegistry)
59+
command: 'buildAndPush'
60+
Dockerfile: 'Dockerfile'
61+
tags: |
62+
$(Build.BuildId)
63+
release-latest
64+
latest
65+
66+
- task: Docker@2
67+
displayName: 'building test docker image'
68+
condition: and(succeeded(), not(eq(variables['ReleaseKind'], 'release')))
69+
inputs:
70+
containerRegistry: $(DockerConnection)
71+
repository: $(DockerRegistry)
72+
command: 'buildAndPush'
73+
Dockerfile: 'Dockerfile'
74+
tags: test-latest
75+

discord-bot-net.sln

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio 15
4-
VisualStudioVersion = 15.0.27703.2035
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.28917.181
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompatBot", "CompatBot\CompatBot.csproj", "{6D9CA448-60C1-4D66-91D6-EC6C586508E6}"
77
EndProject
@@ -17,9 +17,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj
1717
EndProject
1818
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Clients", "Clients", "{E7FE0ADD-CBA6-4321-8A1C-0A3B5C3F54C2}"
1919
EndProject
20-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GithubClient", "Clients\GithubClient\GithubClient.csproj", "{AF8FDA29-864E-4A1C-9568-99DECB7E4B36}"
20+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GithubClient", "Clients\GithubClient\GithubClient.csproj", "{AF8FDA29-864E-4A1C-9568-99DECB7E4B36}"
2121
EndProject
22-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppveyorClient", "Clients\AppveyorClient\AppveyorClient.csproj", "{595ED201-1456-49F9-AD60-54B08499A5C1}"
22+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppveyorClient", "Clients\AppveyorClient\AppveyorClient.csproj", "{595ED201-1456-49F9-AD60-54B08499A5C1}"
23+
EndProject
24+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{AD87F38F-BFCE-4EA6-A430-20C497552FD7}"
25+
ProjectSection(SolutionItems) = preProject
26+
azure-pipelines.yml = azure-pipelines.yml
27+
docker-compose.example.yml = docker-compose.example.yml
28+
Dockerfile = Dockerfile
29+
EndProjectSection
2330
EndProject
2431
Global
2532
GlobalSection(SolutionConfigurationPlatforms) = preSolution

docker-compose.example.yml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
version: "3"
2+
services:
3+
bot:
4+
image: rpcs3/discord-bot:latest
5+
volumes:
6+
- /home/MY_USER_NAME/.local/share/compat-bot:/bot-db
7+
- /home/MY_USER_NAME/.microsoft/usersecrets/c2e6548b-b215-4a18-a010-958ef294b310:/bot-config
8+
- /var/logs/compat-bot:/src/CompatBot/logs
9+
- /ver/ird:/var/ird
10+
environment:
11+
Token: MY_BOT_TOKEN
12+
LogPath: /var/logs/compat-bot
13+
IrdCachePath: /var/ird

0 commit comments

Comments
 (0)