Skip to content

Commit 5aba693

Browse files
committed
Add initial implementation of ViteDevProxy with tests and CI/CD workflow
- Created ViteDevProxy project with service collection extensions for reverse proxy configuration. - Added GitVersion configuration for versioning. - Implemented GitHub Actions workflow for building, testing, and publishing to NuGet. - Added unit and integration tests for ViteDevProxy functionality. - Included .gitignore and solution file for project structure.
0 parents  commit 5aba693

12 files changed

Lines changed: 523 additions & 0 deletions

.github/workflows/publish.yml

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
name: Build and Publish to NuGet
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
release:
9+
types: [ published ]
10+
11+
env:
12+
DOTNET_VERSION: '9.0.x'
13+
PROJECT_PATH: './ViteDevProxy/ViteDevProxy.csproj'
14+
15+
jobs:
16+
build-and-test:
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- uses: actions/checkout@v4
21+
with:
22+
fetch-depth: 0
23+
24+
- name: Setup .NET
25+
uses: actions/setup-dotnet@v4
26+
with:
27+
dotnet-version: ${{ env.DOTNET_VERSION }}
28+
29+
- name: Install GitVersion
30+
uses: gittools/actions/gitversion/setup@v1.2.0
31+
with:
32+
versionSpec: '5.x'
33+
34+
- name: Determine Version
35+
id: gitversion
36+
uses: gittools/actions/gitversion/execute@v1.2.0
37+
with:
38+
useConfigFile: true
39+
40+
- name: Restore dependencies
41+
run: dotnet restore ${{ env.PROJECT_PATH }}
42+
43+
- name: Build
44+
run: dotnet build ${{ env.PROJECT_PATH }} --no-restore --configuration Release -p:Version=${{ steps.gitversion.outputs.nuGetVersionV2 }}
45+
46+
- name: Test
47+
run: dotnet test ./Tests/Tests.csproj --no-build --configuration Release --verbosity normal
48+
49+
publish:
50+
needs: build-and-test
51+
runs-on: ubuntu-latest
52+
if: github.event_name == 'release' && github.event.action == 'published'
53+
54+
steps:
55+
- uses: actions/checkout@v4
56+
with:
57+
fetch-depth: 0
58+
59+
- name: Setup .NET
60+
uses: actions/setup-dotnet@v4
61+
with:
62+
dotnet-version: ${{ env.DOTNET_VERSION }}
63+
64+
- name: Install GitVersion
65+
uses: gittools/actions/gitversion/setup@v1.2.0
66+
with:
67+
versionSpec: '5.x'
68+
69+
- name: Determine Version
70+
id: gitversion
71+
uses: gittools/actions/gitversion/execute@v1.2.0
72+
with:
73+
useConfigFile: true
74+
75+
- name: Restore dependencies
76+
run: dotnet restore ${{ env.PROJECT_PATH }}
77+
78+
- name: Build
79+
run: dotnet build ${{ env.PROJECT_PATH }} --no-restore --configuration Release -p:Version=${{ steps.gitversion.outputs.nuGetVersionV2 }}
80+
81+
- name: Pack
82+
run: dotnet pack ${{ env.PROJECT_PATH }} --no-build --configuration Release -p:PackageVersion=${{ steps.gitversion.outputs.nuGetVersionV2 }} --output ./artifacts
83+
84+
- name: Publish to NuGet
85+
run: dotnet nuget push ./artifacts/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.idea
2+
bin
3+
obj
4+
*.user

GitVersion.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
mode: Mainline
2+
branches:
3+
main:
4+
regex: ^master$|^main$
5+
mode: ContinuousDelivery
6+
tag: ''
7+
increment: Patch
8+
prevent-increment-of-merged-branch-version: true
9+
track-merge-target: false
10+
source-branches: ['develop', 'feature', 'support', 'hotfix']
11+
tracks-release-branches: false
12+
is-release-branch: false
13+
is-mainline: true
14+
develop:
15+
regex: ^develop$
16+
mode: ContinuousDeployment
17+
tag: 'alpha'
18+
increment: Minor
19+
prevent-increment-of-merged-branch-version: false
20+
track-merge-target: true
21+
source-branches: []
22+
tracks-release-branches: true
23+
is-release-branch: false
24+
is-mainline: false
25+
feature:
26+
regex: ^features?[/-]
27+
mode: ContinuousDeployment
28+
tag: 'alpha'
29+
increment: Inherit
30+
prevent-increment-of-merged-branch-version: false
31+
track-merge-target: false
32+
source-branches: ['develop', 'main', 'release', 'feature', 'support', 'hotfix']
33+
tracks-release-branches: false
34+
is-release-branch: false
35+
is-mainline: false
36+
release:
37+
regex: ^releases?[/-]
38+
mode: ContinuousDelivery
39+
tag: 'beta'
40+
increment: Patch
41+
prevent-increment-of-merged-branch-version: true
42+
track-merge-target: false
43+
source-branches: ['develop', 'main', 'support', 'release']
44+
tracks-release-branches: false
45+
is-release-branch: true
46+
is-mainline: false
47+
hotfix:
48+
regex: ^hotfix(es)?[/-]
49+
mode: ContinuousDelivery
50+
tag: 'beta'
51+
increment: Patch
52+
prevent-increment-of-merged-branch-version: false
53+
track-merge-target: false
54+
source-branches: ['release', 'main', 'support', 'hotfix']
55+
tracks-release-branches: false
56+
is-release-branch: false
57+
is-mainline: false
58+
ignore:
59+
sha: []
60+
merge-message-formats: {}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using ViteDevProxy;
3+
using Yarp.ReverseProxy.Configuration;
4+
5+
namespace Tests;
6+
7+
public class ServiceCollectionExtensionsTests
8+
{
9+
[Fact]
10+
public void AddViteDevProxy_WithDefaultUrl_ConfiguresReverseProxy()
11+
{
12+
var services = new ServiceCollection();
13+
14+
var result = services.AddViteDevProxy();
15+
16+
Assert.Same(services, result);
17+
Assert.Contains(services, s => s.ServiceType == typeof(IProxyConfigProvider));
18+
}
19+
20+
[Fact]
21+
public void AddViteDevProxy_WithCustomUrl_ConfiguresReverseProxy()
22+
{
23+
var services = new ServiceCollection();
24+
var customUrl = "http://localhost:3000/";
25+
26+
var result = services.AddViteDevProxy(customUrl);
27+
28+
Assert.Same(services, result);
29+
Assert.Contains(services, s => s.ServiceType == typeof(IProxyConfigProvider));
30+
}
31+
32+
[Fact]
33+
public void AddViteDevProxy_ConfiguresCorrectRouteId()
34+
{
35+
var services = new ServiceCollection();
36+
services.AddViteDevProxy();
37+
38+
var serviceProvider = services.BuildServiceProvider();
39+
var configProvider = serviceProvider.GetService<IProxyConfigProvider>();
40+
41+
Assert.NotNull(configProvider);
42+
}
43+
44+
[Theory]
45+
[InlineData("http://localhost:5173/")]
46+
[InlineData("http://localhost:3000/")]
47+
[InlineData("https://vite.example.com/")]
48+
public void AddViteDevProxy_WithVariousUrls_DoesNotThrow(string viteUrl)
49+
{
50+
var services = new ServiceCollection();
51+
52+
var exception = Record.Exception(() => services.AddViteDevProxy(viteUrl));
53+
54+
Assert.Null(exception);
55+
}
56+
57+
[Fact]
58+
public void AddViteDevProxy_CanBeCalledMultipleTimes()
59+
{
60+
var services = new ServiceCollection();
61+
62+
services.AddViteDevProxy();
63+
var exception = Record.Exception(() => services.AddViteDevProxy("http://localhost:3000/"));
64+
65+
Assert.Null(exception);
66+
}
67+
}

Tests/Tests.csproj

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
<IsPackable>false</IsPackable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="coverlet.collector" Version="6.0.2" />
12+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
13+
<PackageReference Include="xunit" Version="2.9.2" />
14+
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
15+
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="9.0.0" />
16+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
17+
<PackageReference Include="Moq" Version="4.20.72" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<Using Include="Xunit" />
22+
</ItemGroup>
23+
24+
<ItemGroup>
25+
<ProjectReference Include="../ViteDevProxy/ViteDevProxy.csproj" />
26+
</ItemGroup>
27+
28+
</Project>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using ViteDevProxy;
2+
3+
namespace Tests;
4+
5+
public class ViteDevProxyConfigurationTests
6+
{
7+
[Fact]
8+
public void ViteDevProxy_DefaultConfiguration_UsesCorrectDefaults()
9+
{
10+
var expectedDefaultUrl = "http://localhost:5173/";
11+
var expectedRouteId = "vite-dev";
12+
var expectedClusterId = "vite-dev-cluster";
13+
var expectedDestinationId = "vite-dev-destination";
14+
15+
Assert.Equal("http://localhost:5173/", expectedDefaultUrl);
16+
Assert.Equal("vite-dev", expectedRouteId);
17+
Assert.Equal("vite-dev-cluster", expectedClusterId);
18+
Assert.Equal("vite-dev-destination", expectedDestinationId);
19+
}
20+
21+
[Theory]
22+
[InlineData("")]
23+
[InlineData(null)]
24+
public void ViteDevProxy_WithInvalidUrl_DoesNotThrow(string? invalidUrl)
25+
{
26+
var services = new Microsoft.Extensions.DependencyInjection.ServiceCollection();
27+
28+
var exception = Record.Exception(() => services.AddViteDevProxy(invalidUrl!));
29+
30+
Assert.Null(exception);
31+
}
32+
33+
[Fact]
34+
public void ViteDevProxy_RouteConfiguration_CatchesAllPaths()
35+
{
36+
var catchAllPattern = "{**catch-all}";
37+
38+
Assert.Equal("{**catch-all}", catchAllPattern);
39+
}
40+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using ViteDevProxy;
3+
using Yarp.ReverseProxy.Configuration;
4+
5+
namespace Tests;
6+
7+
public class ViteDevProxyConfigurationValidationTests
8+
{
9+
[Fact]
10+
public void ViteDevProxy_Configuration_CreatesValidRouteConfig()
11+
{
12+
var services = new ServiceCollection();
13+
services.AddViteDevProxy("http://localhost:3000/");
14+
15+
var serviceProvider = services.BuildServiceProvider();
16+
var configProvider = serviceProvider.GetRequiredService<IProxyConfigProvider>();
17+
var config = configProvider.GetConfig();
18+
19+
Assert.NotNull(config);
20+
Assert.Single(config.Routes);
21+
Assert.Single(config.Clusters);
22+
}
23+
24+
[Fact]
25+
public void ViteDevProxy_RouteConfig_HasCorrectProperties()
26+
{
27+
var services = new ServiceCollection();
28+
services.AddViteDevProxy();
29+
30+
var serviceProvider = services.BuildServiceProvider();
31+
var configProvider = serviceProvider.GetRequiredService<IProxyConfigProvider>();
32+
var config = configProvider.GetConfig();
33+
34+
var route = config.Routes.First();
35+
Assert.Equal("vite-dev", route.RouteId);
36+
Assert.Equal("vite-dev-cluster", route.ClusterId);
37+
Assert.Equal("{**catch-all}", route.Match.Path);
38+
}
39+
40+
[Fact]
41+
public void ViteDevProxy_ClusterConfig_HasCorrectDestination()
42+
{
43+
var customUrl = "http://localhost:8080/";
44+
var services = new ServiceCollection();
45+
services.AddViteDevProxy(customUrl);
46+
47+
var serviceProvider = services.BuildServiceProvider();
48+
var configProvider = serviceProvider.GetRequiredService<IProxyConfigProvider>();
49+
var config = configProvider.GetConfig();
50+
51+
var cluster = config.Clusters.First();
52+
Assert.Equal("vite-dev-cluster", cluster.ClusterId);
53+
Assert.Single(cluster.Destinations);
54+
Assert.Equal(customUrl, cluster.Destinations["vite-dev-destination"].Address);
55+
}
56+
57+
[Theory]
58+
[InlineData("http://localhost:5173/")]
59+
[InlineData("https://vite-dev.example.com/")]
60+
[InlineData("http://192.168.1.100:3000/")]
61+
public void ViteDevProxy_WithDifferentUrls_ConfiguresCorrectly(string viteUrl)
62+
{
63+
var services = new ServiceCollection();
64+
services.AddViteDevProxy(viteUrl);
65+
66+
var serviceProvider = services.BuildServiceProvider();
67+
var configProvider = serviceProvider.GetRequiredService<IProxyConfigProvider>();
68+
var config = configProvider.GetConfig();
69+
70+
var destination = config.Clusters.First().Destinations.First().Value;
71+
Assert.Equal(viteUrl, destination.Address);
72+
}
73+
}

0 commit comments

Comments
 (0)