diff --git a/.github/workflows/UploadDockerImage.yml b/.github/workflows/UploadDockerImage.yml
new file mode 100644
index 000000000..5b66f9db0
--- /dev/null
+++ b/.github/workflows/UploadDockerImage.yml
@@ -0,0 +1,43 @@
+name: Upload Docker Images
+
+on:
+ # Manually trigger on specific branches
+ workflow_dispatch:
+ push:
+ branches:
+ - main
+
+permissions:
+ id-token: write
+
+jobs:
+ upload-docker-images:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Configure AWS Credentials
+ uses: aws-actions/configure-aws-credentials@8c3f20df09ac63af7b3ae3d7c91f105f857d8497 #v4
+ with:
+ aws-region: us-west-2
+ role-to-assume: ${{ secrets.DOCKER_IMAGE_UPLOADER_ROLE }}
+ role-duration-seconds: 1800
+
+ - name: Checkout Repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET Core 6.0
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: 6.0.x
+
+ - name: Restore dependencies
+ run: dotnet restore
+
+ - name: Build
+ run: dotnet build --no-restore
+
+ - name: Run Docker Image Uploader
+ run: |
+ cd ./src/AWS.Deploy.DockerImageUploader
+ dotnet run --project ./AWS.Deploy.DockerImageUploader.csproj
\ No newline at end of file
diff --git a/AWS.Deploy.sln b/AWS.Deploy.sln
index 6540ad553..5c446ad04 100644
--- a/AWS.Deploy.sln
+++ b/AWS.Deploy.sln
@@ -67,6 +67,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AWS.Deploy.DocGenerator", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AWS.Deploy.DocGenerator.UnitTests", "test\AWS.Deploy.DocGenerator.UnitTests\AWS.Deploy.DocGenerator.UnitTests.csproj", "{7E661545-7DFD-4FE3-A5F9-767FAE30DFFE}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AWS.Deploy.DockerImageUploader", "src\AWS.Deploy.DockerImageUploader\AWS.Deploy.DockerImageUploader.csproj", "{407D6B9B-E831-4DD2-9270-A7913A7A09D1}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -173,6 +175,10 @@ Global
{7E661545-7DFD-4FE3-A5F9-767FAE30DFFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E661545-7DFD-4FE3-A5F9-767FAE30DFFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E661545-7DFD-4FE3-A5F9-767FAE30DFFE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {407D6B9B-E831-4DD2-9270-A7913A7A09D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {407D6B9B-E831-4DD2-9270-A7913A7A09D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {407D6B9B-E831-4DD2-9270-A7913A7A09D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {407D6B9B-E831-4DD2-9270-A7913A7A09D1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -204,6 +210,7 @@ Global
{CEEBEC39-40E5-4A9B-878A-6EDB52B9B43E} = {C3A0C716-BDEA-4393-B223-AF8F8531522A}
{6D4BD0C2-C2A0-4AFB-BC22-623DD64A4F84} = {11C7056E-93C1-408B-BD87-5270595BBE0E}
{7E661545-7DFD-4FE3-A5F9-767FAE30DFFE} = {BD466B5C-D8B0-4069-98A9-6DC8F01FA757}
+ {407D6B9B-E831-4DD2-9270-A7913A7A09D1} = {11C7056E-93C1-408B-BD87-5270595BBE0E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5A4B2863-1763-4496-B122-651A38A4F5D7}
diff --git a/src/AWS.Deploy.DockerImageUploader/AWS.Deploy.DockerImageUploader.csproj b/src/AWS.Deploy.DockerImageUploader/AWS.Deploy.DockerImageUploader.csproj
new file mode 100644
index 000000000..41b04e51b
--- /dev/null
+++ b/src/AWS.Deploy.DockerImageUploader/AWS.Deploy.DockerImageUploader.csproj
@@ -0,0 +1,13 @@
+
+
+
+ Exe
+ net6.0
+ enable
+
+
+
+
+
+
+
diff --git a/src/AWS.Deploy.DockerImageUploader/App.cs b/src/AWS.Deploy.DockerImageUploader/App.cs
new file mode 100644
index 000000000..29ba67b38
--- /dev/null
+++ b/src/AWS.Deploy.DockerImageUploader/App.cs
@@ -0,0 +1,72 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+using AWS.Deploy.Common.IO;
+using AWS.Deploy.Common;
+using Microsoft.Extensions.DependencyInjection;
+using System.Reflection;
+using System.Collections.Generic;
+using System;
+using System.Threading.Tasks;
+using System.IO;
+
+namespace AWS.Deploy.DockerImageUploader
+{
+ public class App
+ {
+ private readonly IFileManager _fileManager;
+ private readonly IDirectoryManager _directoryManager;
+ private readonly IProjectDefinitionParser _projectDefinitionParser;
+ private readonly CLI.App _deployToolCli;
+
+ private readonly List _testApps = new List { "WebApiNET6", "ConsoleAppTask" };
+
+ public App(IServiceProvider serviceProvider)
+ {
+ _projectDefinitionParser = serviceProvider.GetRequiredService();
+ _fileManager = serviceProvider.GetRequiredService();
+ _directoryManager = serviceProvider.GetRequiredService();
+ _deployToolCli = serviceProvider.GetRequiredService();
+ }
+
+ public async Task Run(string[] args)
+ {
+ foreach (var testApp in _testApps)
+ {
+ var projectPath = ResolvePath(testApp);
+ await CreateImageAndPushToECR(projectPath);
+ }
+ }
+
+ private async Task CreateImageAndPushToECR(string projectPath)
+ {
+ var projectDefinition = await _projectDefinitionParser.Parse(projectPath);
+
+ var dockerEngine = new DockerEngine.DockerEngine(projectDefinition, _fileManager, _directoryManager);
+
+ dockerEngine.GenerateDockerFile();
+
+ var configFilePath = Path.Combine(projectPath, "DockerImageUploaderConfigFile.json");
+
+ var deployArgs = new[] { "deploy", "--project-path", projectPath, "--diagnostics", "--apply", configFilePath, "--silent" };
+ await _deployToolCli.Run(deployArgs);
+ }
+
+ private string ResolvePath(string projectName)
+ {
+ const string srcDir = "src";
+ var srcDirPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+ while (srcDirPath != null && !string.Equals(new DirectoryInfo(srcDirPath).Name, srcDir, StringComparison.OrdinalIgnoreCase))
+ {
+ srcDirPath = Directory.GetParent(srcDirPath)?.FullName;
+ }
+
+ if (string.IsNullOrEmpty(srcDirPath))
+ {
+ throw new Exception($"Failed to find path to '{srcDir}' directory.");
+ }
+
+ return Path.Combine(srcDirPath, "..", "testapps", projectName);
+ }
+ }
+}
diff --git a/src/AWS.Deploy.DockerImageUploader/Program.cs b/src/AWS.Deploy.DockerImageUploader/Program.cs
new file mode 100644
index 000000000..1240a7f29
--- /dev/null
+++ b/src/AWS.Deploy.DockerImageUploader/Program.cs
@@ -0,0 +1,32 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+using Microsoft.Extensions.DependencyInjection;
+using AWS.Deploy.CLI.Extensions;
+using System.Threading.Tasks;
+using System;
+
+namespace AWS.Deploy.DockerImageUploader
+{
+ internal class Program
+ {
+ public static async Task Main(string[] args)
+ {
+ var serviceCollection = new ServiceCollection();
+
+ serviceCollection.AddCustomServices();
+ serviceCollection.AddSingleton();
+
+ var serviceProvider = serviceCollection.BuildServiceProvider();
+
+ var app = serviceProvider.GetService();
+ if (app == null)
+ {
+ throw new Exception("App dependencies aren't injected correctly." +
+ " Verify that all the required dependencies to instantiate DockerImageUploader are present.");
+ }
+
+ await app.Run(args);
+ }
+ }
+}
diff --git a/testapps/ConsoleAppTask/DockerImageUploaderConfigFile.json b/testapps/ConsoleAppTask/DockerImageUploaderConfigFile.json
new file mode 100644
index 000000000..fcc40ce0e
--- /dev/null
+++ b/testapps/ConsoleAppTask/DockerImageUploaderConfigFile.json
@@ -0,0 +1,7 @@
+{
+ "RecipeId": "PushContainerImageEcr",
+ "settings": {
+ "ImageTag": "latest",
+ "ECRRepositoryName": "deploytool-consoleapp"
+ }
+}
diff --git a/testapps/WebApiNET6/DockerImageUploaderConfigFile.json b/testapps/WebApiNET6/DockerImageUploaderConfigFile.json
new file mode 100644
index 000000000..51d813572
--- /dev/null
+++ b/testapps/WebApiNET6/DockerImageUploaderConfigFile.json
@@ -0,0 +1,7 @@
+{
+ "RecipeId": "PushContainerImageEcr",
+ "settings": {
+ "ImageTag": "latest",
+ "ECRRepositoryName": "deploytool-webapp"
+ }
+}