mirror of
				https://github.com/TheLartians/ModernCppStarter.git
				synced 2025-10-31 10:11:34 +01:00 
			
		
		
		
	Merge d36cb2e388 into 12cf5de1a8
				
					
				
			This commit is contained in:
		
						commit
						e4d34b3edc
					
				
					 8 changed files with 256 additions and 49 deletions
				
			
		
							
								
								
									
										6
									
								
								.dockerignore
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.dockerignore
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | ||||||
|  | /build* | ||||||
|  | /.vscode | ||||||
|  | /cpm_modules | ||||||
|  | .DS_Store | ||||||
|  | /.github | ||||||
|  | /standalone/Dockerfile | ||||||
							
								
								
									
										94
									
								
								.github/workflows/docker-cd.yml
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								.github/workflows/docker-cd.yml
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,94 @@ | ||||||
|  | name: run Docker CD | ||||||
|  | 
 | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |     tags: | ||||||
|  |       - "v*.*.*" | ||||||
|  |   workflow_dispatch: | ||||||
|  |     inputs: | ||||||
|  |       tag: | ||||||
|  |         description: "Test scenario tag" | ||||||
|  |         required: true | ||||||
|  |         default: "test" | ||||||
|  |       set-latest-tag: | ||||||
|  |         description: "Also set the 'latest' tag with this run? (y/n)" | ||||||
|  |         required: true | ||||||
|  |         default: "n" | ||||||
|  | 
 | ||||||
|  | env: | ||||||
|  |   CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm_modules | ||||||
|  | 
 | ||||||
|  | jobs: | ||||||
|  |   build: | ||||||
|  |     name: CD build docker and push to DockerHub | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  | 
 | ||||||
|  |     steps: | ||||||
|  |       - uses: actions/checkout@v2 | ||||||
|  | 
 | ||||||
|  |       - name: handle manual workflow start and prepare docker image tag(s) | ||||||
|  |         id: docker-tags | ||||||
|  |         shell: bash | ||||||
|  |         run: | | ||||||
|  |           if [[ "x${{ github.event.inputs.tag }}" != "x" ]]; then | ||||||
|  |             echo "Workflow started via workflow_dispatch! Parameters: tag=${{ github.event.inputs.tag }}, set-latest-tag=${{ github.event.inputs.set-latest-tag }}" | ||||||
|  |             tag="${{ github.event.inputs.tag }}" | ||||||
|  |           else | ||||||
|  |             echo "Workflow started via push with tag! Complete tag: ${GITHUB_REF:10}" | ||||||
|  |             tag="${GITHUB_REF:11}" | ||||||
|  |           fi | ||||||
|  | 
 | ||||||
|  |           if [[ "x${{ github.event.inputs.set-latest-tag }}" == "xy" || "x${{ github.event.inputs.tag }}" == "x" ]]; then | ||||||
|  |             tags="${{ secrets.DOCKERHUB_USERNAME }}/greeter-webapi:$tag, ${{ secrets.DOCKERHUB_USERNAME }}/greeter-webapi:latest" | ||||||
|  |             echo "Docker image release tags: $tags" | ||||||
|  |           else | ||||||
|  |             tags="${{ secrets.DOCKERHUB_USERNAME }}/greeter-webapi:$tag" | ||||||
|  |             echo "Docker image release tag: $tags" | ||||||
|  |           fi | ||||||
|  | 
 | ||||||
|  |           echo ::set-output name=tags::$tags | ||||||
|  | 
 | ||||||
|  |       # | ||||||
|  |       # configure and build in GitHub CI as smoke test | ||||||
|  | 
 | ||||||
|  |       # speed up configure step by installing boost as system lib, also use Ninja for faster builds | ||||||
|  |       - name: speed up configure and build | ||||||
|  |         shell: bash | ||||||
|  |         run: sudo apt-get update && sudo apt-get install -y libboost-all-dev ninja-build | ||||||
|  | 
 | ||||||
|  |       # use GitHub cache to cache dependencies | ||||||
|  |       - uses: actions/cache@v2 | ||||||
|  |         with: | ||||||
|  |           path: "**/cpm_modules" | ||||||
|  |           key: ${{ github.workflow }}-cpm-modules-${{ hashFiles('**/CMakeLists.txt', '**/*.cmake') }} | ||||||
|  | 
 | ||||||
|  |       - name: configure | ||||||
|  |         run: cmake -S standalone -B build -G Ninja -D CMAKE_BUILD_TYPE=Release | ||||||
|  | 
 | ||||||
|  |       - name: build | ||||||
|  |         run: cmake --build build | ||||||
|  | 
 | ||||||
|  |       # | ||||||
|  |       # end GitHub CI local build | ||||||
|  | 
 | ||||||
|  |       - name: set up Docker Buildx for multi-platform support | ||||||
|  |         uses: docker/setup-buildx-action@v1 | ||||||
|  | 
 | ||||||
|  |       - name: set up QEMU for multi-platform support | ||||||
|  |         uses: docker/setup-qemu-action@v1 | ||||||
|  | 
 | ||||||
|  |       - name: login to DockerHub | ||||||
|  |         uses: docker/login-action@v1 | ||||||
|  |         with: | ||||||
|  |           username: ${{ secrets.DOCKERHUB_USERNAME }} | ||||||
|  |           password: ${{ secrets.DOCKERHUB_TOKEN }} | ||||||
|  | 
 | ||||||
|  |       - name: build Docker image and push to DockerHub | ||||||
|  |         uses: docker/build-push-action@v2 | ||||||
|  |         with: | ||||||
|  |           file: ./standalone/Dockerfile | ||||||
|  |           platforms: linux/amd64,linux/arm64 | ||||||
|  |           push: true | ||||||
|  |           tags: ${{ steps.docker-tags.outputs.tags }} | ||||||
|  |           cache-from: type=gha | ||||||
|  |           cache-to: type=gha,mode=max | ||||||
							
								
								
									
										63
									
								
								.github/workflows/docker-ci.yml
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								.github/workflows/docker-ci.yml
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | ||||||
|  | name: run Docker CI | ||||||
|  | 
 | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |     branches: | ||||||
|  |       - main | ||||||
|  |       - master | ||||||
|  |       - add-docker-build | ||||||
|  |   pull_request: | ||||||
|  |     branches: | ||||||
|  |       - main | ||||||
|  |       - master | ||||||
|  | 
 | ||||||
|  | env: | ||||||
|  |   CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm_modules | ||||||
|  | 
 | ||||||
|  | jobs: | ||||||
|  |   build: | ||||||
|  |     name: CI build docker | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  | 
 | ||||||
|  |     steps: | ||||||
|  |       - uses: actions/checkout@v2 | ||||||
|  | 
 | ||||||
|  |       # | ||||||
|  |       # configure and build in GitHub CI as smoke test | ||||||
|  | 
 | ||||||
|  |       # speed up configure step by installing boost as system lib, also use Ninja for faster builds | ||||||
|  |       - name: speed up configure and build | ||||||
|  |         shell: bash | ||||||
|  |         run: sudo apt-get update && sudo apt-get install -y libboost-all-dev ninja-build | ||||||
|  | 
 | ||||||
|  |       # use GitHub cache to cache dependencies | ||||||
|  |       - uses: actions/cache@v2 | ||||||
|  |         with: | ||||||
|  |           path: "**/cpm_modules" | ||||||
|  |           key: ${{ github.workflow }}-cpm-modules-${{ hashFiles('**/CMakeLists.txt', '**/*.cmake') }} | ||||||
|  | 
 | ||||||
|  |       - name: configure | ||||||
|  |         run: cmake -S standalone -B build -G Ninja -D CMAKE_BUILD_TYPE=Release | ||||||
|  | 
 | ||||||
|  |       - name: build | ||||||
|  |         run: cmake --build build | ||||||
|  | 
 | ||||||
|  |       # | ||||||
|  |       # end GitHub CI local build | ||||||
|  | 
 | ||||||
|  |       - name: set up Docker Buildx for multi-platform support | ||||||
|  |         uses: docker/setup-buildx-action@v1 | ||||||
|  | 
 | ||||||
|  |       - name: set up QEMU for multi-platform support | ||||||
|  |         uses: docker/setup-qemu-action@v1 | ||||||
|  | 
 | ||||||
|  |       # build image but do NOT push to DockerHub | ||||||
|  |       - name: build Docker image | ||||||
|  |         uses: docker/build-push-action@v2 | ||||||
|  |         with: | ||||||
|  |           file: ./standalone/Dockerfile | ||||||
|  |           platforms: linux/amd64,linux/arm64 | ||||||
|  |           push: false | ||||||
|  |           tags: ${{ secrets.DOCKERHUB_USERNAME }}/greeter-webapi:ci | ||||||
|  |           cache-from: type=gha | ||||||
|  |           cache-to: type=gha,mode=max | ||||||
							
								
								
									
										2
									
								
								.github/workflows/standalone.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/standalone.yml
									
										
									
									
										vendored
									
									
								
							|  | @ -32,4 +32,4 @@ jobs: | ||||||
|         run: cmake --build build -j4 |         run: cmake --build build -j4 | ||||||
| 
 | 
 | ||||||
|       - name: run |       - name: run | ||||||
|         run: ./build/Greeter |         run: ./build/GreeterStandalone | ||||||
|  |  | ||||||
|  | @ -1,6 +1,10 @@ | ||||||
| cmake_minimum_required(VERSION 3.14...3.22) | cmake_minimum_required(VERSION 3.14...3.22) | ||||||
| 
 | 
 | ||||||
| project(GreeterStandalone LANGUAGES CXX) | project( | ||||||
|  |   GreeterStandalone | ||||||
|  |   DESCRIPTION "A standalone minimal webapi application using the Crow framework" | ||||||
|  |   LANGUAGES CXX | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| # --- Import tools ---- | # --- Import tools ---- | ||||||
| 
 | 
 | ||||||
|  | @ -10,12 +14,38 @@ include(../cmake/tools.cmake) | ||||||
| 
 | 
 | ||||||
| include(../cmake/CPM.cmake) | include(../cmake/CPM.cmake) | ||||||
| 
 | 
 | ||||||
|  | # Crow needs Boost 1.64 and does not provide CPM.cmake integration itself, so we have to get Boost | ||||||
|  | # first | ||||||
|  | find_package(Boost 1.64 QUIET) | ||||||
|  | if(NOT Boost_FOUND) | ||||||
|  |   # Use CPM.cmake to get Boost from the official repo if not provided as system lib | ||||||
|  |   message(STATUS "GreeterStandalone: Boost system lib NOT found") | ||||||
|   CPMAddPackage( |   CPMAddPackage( | ||||||
|   GITHUB_REPOSITORY jarro2783/cxxopts |     NAME Boost | ||||||
|   VERSION 3.0.0 |     GITHUB_REPOSITORY boostorg/boost | ||||||
|   OPTIONS "CXXOPTS_BUILD_EXAMPLES NO" "CXXOPTS_BUILD_TESTS NO" "CXXOPTS_ENABLE_INSTALL YES" |     GIT_TAG boost-1.78.0 | ||||||
|  |     VERSION 1.78.0 | ||||||
|  |   ) | ||||||
|  |   # Ugly workaround: Boost cmake support is still experimental, the Boost::boost target is not | ||||||
|  |   # provided if downloaded via FetchContent_declare / CPM.cmake. Crow uses it for asio, so we fake | ||||||
|  |   # the Boost:boost target as asio | ||||||
|  |   if(NOT TARGET Boost::boost) | ||||||
|  |     add_library(Boost::boost INTERFACE IMPORTED) | ||||||
|  |     target_link_libraries(Boost::boost INTERFACE Boost::asio) | ||||||
|  |   endif() | ||||||
|  | else() | ||||||
|  |   message(STATUS "GreeterStandalone: Boost system lib found") | ||||||
|  | endif() | ||||||
|  | # add Crow | ||||||
|  | CPMAddPackage( | ||||||
|  |   NAME Crow | ||||||
|  |   GITHUB_REPOSITORY CrowCpp/Crow | ||||||
|  |   GIT_TAG v1.0+1 | ||||||
|  |   VERSION 1.0.1 | ||||||
|  |   OPTIONS "CROW_INSTALL OFF" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | # get the Greeter lib | ||||||
| CPMAddPackage(NAME Greeter SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/..) | CPMAddPackage(NAME Greeter SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/..) | ||||||
| 
 | 
 | ||||||
| # ---- Create standalone executable ---- | # ---- Create standalone executable ---- | ||||||
|  | @ -23,7 +53,5 @@ CPMAddPackage(NAME Greeter SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/..) | ||||||
| file(GLOB sources CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp) | file(GLOB sources CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp) | ||||||
| 
 | 
 | ||||||
| add_executable(${PROJECT_NAME} ${sources}) | add_executable(${PROJECT_NAME} ${sources}) | ||||||
| 
 | target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_11) | ||||||
| set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 17 OUTPUT_NAME "Greeter") | target_link_libraries(${PROJECT_NAME} PRIVATE Greeter::Greeter Crow::Crow) | ||||||
| 
 |  | ||||||
| target_link_libraries(${PROJECT_NAME} Greeter::Greeter cxxopts) |  | ||||||
|  |  | ||||||
							
								
								
									
										21
									
								
								standalone/Dockerfile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								standalone/Dockerfile
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | ||||||
|  | # build | ||||||
|  | FROM buildpack-deps:bullseye as webapp-build | ||||||
|  | RUN set -eux; \ | ||||||
|  |     apt-get update; \ | ||||||
|  |     apt-get install -y --no-install-recommends \ | ||||||
|  |     cmake \ | ||||||
|  |     ninja-build \ | ||||||
|  |     # configure/build with Boost as system lib - this should be orders of magnitude faster to configure than | ||||||
|  |     # downloading via CPM.cmake while Boost's CMake support is still experimental | ||||||
|  |     libboost-all-dev \ | ||||||
|  |     ; | ||||||
|  | COPY . . | ||||||
|  | RUN cmake -S standalone -B build -G Ninja -D CMAKE_BUILD_TYPE=Release | ||||||
|  | RUN cmake --build build | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # deploy | ||||||
|  | FROM debian:bullseye-slim as webapp-run | ||||||
|  | WORKDIR /app | ||||||
|  | COPY --from=webapp-build /build/GreeterStandalone . | ||||||
|  | CMD ["./GreeterStandalone"] | ||||||
|  | @ -1,53 +1,48 @@ | ||||||
|  | #include <crow.h> | ||||||
| #include <greeter/greeter.h> | #include <greeter/greeter.h> | ||||||
| #include <greeter/version.h> | #include <greeter/version.h> | ||||||
| 
 | 
 | ||||||
| #include <cxxopts.hpp> |  | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <string> | #include <string> | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
| 
 | 
 | ||||||
| auto main(int argc, char** argv) -> int { | int main() { | ||||||
|  |   crow::SimpleApp app; | ||||||
|  | 
 | ||||||
|  |   CROW_ROUTE(app, "/hello") | ||||||
|  |   ([](const crow::request& req) { | ||||||
|  |     // check params
 | ||||||
|  |     std::cout << "Params: " << req.url_params << "\n"; | ||||||
|  |     std::cout << "The key 'language' was " | ||||||
|  |               << (req.url_params.get("language") == nullptr ? "not " : "") << "found.\n"; | ||||||
|  | 
 | ||||||
|  |     if (req.url_params.get("language") == nullptr) { | ||||||
|  |       // return bad request
 | ||||||
|  |       return crow::response(400, "please provide a 'language' argument"); | ||||||
|  |     } | ||||||
|  |     const auto language = req.url_params.get("language"); | ||||||
|  | 
 | ||||||
|  |     // see if langauge was found
 | ||||||
|     const std::unordered_map<std::string, greeter::LanguageCode> languages{ |     const std::unordered_map<std::string, greeter::LanguageCode> languages{ | ||||||
|         {"en", greeter::LanguageCode::EN}, |         {"en", greeter::LanguageCode::EN}, | ||||||
|         {"de", greeter::LanguageCode::DE}, |         {"de", greeter::LanguageCode::DE}, | ||||||
|         {"es", greeter::LanguageCode::ES}, |         {"es", greeter::LanguageCode::ES}, | ||||||
|         {"fr", greeter::LanguageCode::FR}, |         {"fr", greeter::LanguageCode::FR}, | ||||||
|     }; |     }; | ||||||
| 
 |     const auto langIt = languages.find(language); | ||||||
|   cxxopts::Options options(*argv, "A program to welcome the world!"); |  | ||||||
| 
 |  | ||||||
|   std::string language; |  | ||||||
|   std::string name; |  | ||||||
| 
 |  | ||||||
|   // clang-format off
 |  | ||||||
|   options.add_options() |  | ||||||
|     ("h,help", "Show help") |  | ||||||
|     ("v,version", "Print the current version number") |  | ||||||
|     ("n,name", "Name to greet", cxxopts::value(name)->default_value("World")) |  | ||||||
|     ("l,lang", "Language code to use", cxxopts::value(language)->default_value("en")) |  | ||||||
|   ; |  | ||||||
|   // clang-format on
 |  | ||||||
| 
 |  | ||||||
|   auto result = options.parse(argc, argv); |  | ||||||
| 
 |  | ||||||
|   if (result["help"].as<bool>()) { |  | ||||||
|     std::cout << options.help() << std::endl; |  | ||||||
|     return 0; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   if (result["version"].as<bool>()) { |  | ||||||
|     std::cout << "Greeter, version " << GREETER_VERSION << std::endl; |  | ||||||
|     return 0; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   auto langIt = languages.find(language); |  | ||||||
|     if (langIt == languages.end()) { |     if (langIt == languages.end()) { | ||||||
|     std::cerr << "unknown language code: " << language << std::endl; |       // return bad request
 | ||||||
|     return 1; |       std::cout << "Greeting for language '" << language << "' is not available\n"; | ||||||
|  |       return crow::response(400, "language not recognized"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|   greeter::Greeter greeter(name); |     const greeter::Greeter greeter("Crow & Greeter"); | ||||||
|   std::cout << greeter.greet(langIt->second) << std::endl; |     std::cout << "Greeting for language '" << language << "' is available, returning message\n"; | ||||||
|  |     const auto message = greeter.greet(langIt->second); | ||||||
| 
 | 
 | ||||||
|   return 0; |     crow::json::wvalue ret({{"answer", message}}); | ||||||
|  |     return crow::response(200, ret); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   app.port(3080).multithreaded().run(); | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue