diff --git a/.github/workflows/build-deploy.yml b/.github/workflows/build-deploy.yml new file mode 100644 index 00000000000..ede1f295fa6 --- /dev/null +++ b/.github/workflows/build-deploy.yml @@ -0,0 +1,56 @@ +name: Build and Deploy + +on: + push: + branches: + - "deploy" # Trigger on push to any branch + pull_request: + branches: + - "deploy" # Trigger on pull request to any branch + +jobs: + build_and_deploy: + name: Build and Deploy Job # Define the name of the job + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 # Checkout the repository code + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: "18.20.2" # Set up Node.js version 18 + + - name: Customize dependencies + if: ${{ env.WL_Customization != null }} # Conditional step execution + run: | + git clone --recurse-submodules ${WL_Customization} sunbirded-portal # Clone repository with submodules + cp -r sunbirded-portal/images/ src/app/client/src/assets # Copy images to client assets + cp -r sunbirded-portal/resourceBundles/data/ src/app/resourcebundles/ # Copy resource bundle data + env: + WL_Customization: ${{ github.event.inputs.WL_Customization }} # Set environment variable WL_Customization + + - name: Build and Create Docker Image + run: | + commit_hash=$(git rev-parse --short HEAD) # Get commit hash + build_tag=$(echo "${{ github.ref }}" | rev | cut -d/ -f1 | rev)_${commit_hash}_${GITHUB_RUN_NUMBER} # Generate build tag + echo "build_tag: $build_tag" # Print build tag + bash ./build.sh "${build_tag}" "${{ env.NODE_NAME }}" "test" true false "" # Run build script with parameters + env: + NODE_NAME: "18.20.2" # Set environment variable NODE_NAME + + - name: Archive Artifacts + uses: actions/upload-artifact@v2 + with: + name: metadata + path: metadata.json + + - name: Archive CDN assets if required + if: ${{ github.event.inputs.buildCdnAssests == 'true' }} # Conditional step execution + run: | + rm -rf cdn_assets # Remove existing CDN assets directory + mkdir cdn_assets # Create CDN assets directory + cp -r src/app/dist-cdn/* cdn_assets/ # Copy CDN assets + zip -Jr cdn_assets.zip cdn_assets # Create zip file of CDN assets + echo "##vso[task.uploadfile]cdn_assets.zip" # Upload CDN assets zip file diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 9f46399d100..5c08225c2c9 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -23,70 +23,65 @@ jobs: with: node-version: 18 - # Install client dependencies - - name: Install client dependencies - working-directory: src/app/client - run: yarn install --no-progress --production=true - - # Build the client - - name: Build client - working-directory: src/app/client - run: npm run build - - # List all files after the build - - name: List all files after build - working-directory: src/app/client - run: find . -type f - - # Check if the dist directory exists and list its contents - - name: Check if dist directory exists and list contents - working-directory: src/app/client - run: | - if [ -d dist ]; then - echo "dist directory exists. Listing contents:" - ls -l dist - else - echo "dist directory does not exist" - fi - - # Move index.html to index.ejs if it exists - - name: Move index.html to index.ejs if it exists - working-directory: src/app/client - run: | - if [ -f dist/index.html ]; then - mv dist/index.html dist/index.ejs - else - echo "File dist/index.html does not exist" - fi - - # Set up server directories - - name: Set up server directories - run: mkdir -p $GITHUB_WORKSPACE/app_dist - - # Copy server files to the destination directory - - name: Copy server files - run: | - cp -r src/app/libs src/app/helpers src/app/proxy src/app/resourcebundles src/app/package.json src/app/framework.config.js src/app/sunbird-plugins src/app/routes src/app/constants src/app/controllers src/app/server.js $GITHUB_WORKSPACE/app_dist/ - shell: /usr/bin/bash -e {0} - - # Install server dependencies - - name: Install server dependencies - working-directory: ${{ github.workspace }}/app_dist - run: yarn install --ignore-engines --no-progress --production=true - - # Run server build script - - name: Run server build script - working-directory: ${{ github.workspace }}/app_dist - run: node helpers/resourceBundles/build.js -task="phraseAppPull" + # # Install client dependencies + # - name: Install client dependencies + # working-directory: src/app/client + # run: yarn install --no-progress --production=true + # # Build the client + # - name: Build client + # working-directory: src/app/client + # run: npm run build + # # List all files after the build + # - name: List all files after build + # working-directory: src/app/client + # run: find . -type f + # # Check if the dist directory exists and list its contents + # - name: Check if dist directory exists and list contents + # working-directory: src/app/client + # run: | + # if [ -d dist ]; then + # echo "dist directory exists. Listing contents:" + # ls -l dist + # else + # echo "dist directory does not exist" + # fi + # # Move index.html to index.ejs if it exists + # - name: Move index.html to index.ejs if it exists + # working-directory: src/app/client + # run: | + # if [ -f dist/index.html ]; then + # mv dist/index.html dist/index.ejs + # else + # echo "File dist/index.html does not exist" + # fi + # # Set up server directories + # - name: Set up server directories + # run: mkdir -p $GITHUB_WORKSPACE/app_dist + # # Copy server files to the destination directory + # - name: Copy server files + # run: | + # cp -r src/app/libs src/app/helpers src/app/proxy src/app/resourcebundles src/app/package.json src/app/framework.config.js src/app/sunbird-plugins src/app/routes src/app/constants src/app/controllers src/app/server.js $GITHUB_WORKSPACE/app_dist/ + # shell: /usr/bin/bash -e {0} + # # Install server dependencies + # - name: Install server dependencies + # working-directory: ${{ github.workspace }}/app_dist + # run: yarn install --ignore-engines --no-progress --production=true + # # Run server build script + # - name: Run server build script + # working-directory: ${{ github.workspace }}/app_dist + # run: node helpers/resourceBundles/build.js -task="phraseAppPull" # Execute test cases using JEST - - name: Execute test cases using JEST - working-directory: src/app/client - run: | - yarn config set ignore-engines true - yarn install - npm run test:ci + # - name: Execute test cases using JEST + # working-directory: src/app/client + # run: | + # yarn config set ignore-engines true + # yarn install + # npm run test:ci + # Debug: Print the masked SONAR_TOKEN + - name: Print SONAR_TOKEN + run: echo "SONAR_TOKEN=${{ secrets.SONAR_TOKEN }}PWR****123" - # Install Sonar Scanner + #Install Sonar Scanner - name: Install Sonar Scanner run: | cd /tmp @@ -95,12 +90,62 @@ jobs: unzip sonar-scanner-cli-5.0.1.3006-linux.zip cd - - - name: Run Sonar Scanner + # Run SonarScanner for frontend (Angular) + - name: Run SonarScanner for frontend env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: | /tmp/sonar-scanner-5.0.1.3006-linux/bin/sonar-scanner \ - -Dsonar.projectKey=Sunbird-Ed_SunbirdEd-portal \ - -Dsonar.organization=sunbird-ed \ + -Dsonar.sources=src/app/client/src \ -Dsonar.host.url=https://sonarcloud.io \ -Dsonar.login=$SONAR_TOKEN + + # - name: Run Sonar Scanner + # env: + # SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + # run: | + # /tmp/sonar-scanner-5.0.1.3006-linux/bin/sonar-scanner \ + # -Dsonar.projectKey=Sunbird-Ed_SunbirdEd-portal \ + # -Dsonar.sources=src/app/client/src \ + # -Dsonar.organization=sunbird-ed \ + # -Dsonar.host.url=https://sonarcloud.io \ + # -Dsonar.login=$SONAR_TOKEN + + # Install SonarScanner globally using npm + # - name: Install SonarScanner + # run: + # npm install -g sonarqube-scanner + + # # Check if SONAR_TOKEN is set + # - name: Check SONAR_TOKEN + # run: | + # if [ -z "${{ secrets.SONAR_TOKEN }}" ]; then + # echo "Error: SONAR_TOKEN is not set." + + # else + # echo "SONAR_TOKEN is set." + # fi + + # Debug: Print the masked SONAR_TOKEN + # - name: Print SONAR_TOKEN + # run: echo "SONAR_TOKEN=${{ secrets.SONAR_TOKEN }}PWR****123" + # # Ensure sonar-project.properties exists and print its content for debugging + # - name: Check sonar-project.properties + # run: | + # if [ -f sonar-project.properties ]; then + # echo "Found sonar-project.properties" + # cat sonar-project.properties + # else + # echo "sonar-project.properties not found" + # fi + # # Run SonarScanner in the specified directory + # - name: Run SonarScanner + # env: + # SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + # run: | + # sonar-scanner \ + # -Dsonar.projectKey=Sunbird-Ed_SunbirdEd-portal \ + # -Dsonar.organization=sunbird-ed \ + # -Dsonar.sources=src/app/client/src \ + # -Dsonar.host.url=https://sonarcloud.io \ + # -Dsonar.login=$SONAR_TOKEN diff --git a/Dockerfile b/Dockerfile index 8eb8dbc141a..e460026cc31 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,113 @@ -# Dockerfile for the player setup +# Use a base image suitable for building the client and server +FROM node:18.20.2-slim AS builder + +# Arguments for CDN URL and buildCdnAssets +ARG cdnUrl="" +ENV cdnUrl=${cdnUrl} +ARG buildCdnAssets="" +ENV buildCdnAssets=${buildCdnAssets} + +# Set the working directory for the client build +WORKDIR /usr/src/app/client +# Install npm +RUN apt-get update && apt-get install -y npm + +# Install Yarn +RUN npm install -g yarn --force + +# Copy the client code into the Docker container +COPY src/app/client ./ +RUN rm -rf node_modules yarn.lock +RUN yarn cache clean + + +# Install client dependencies +RUN yarn install --no-progress --frozen-lockfile --production=true + + +# Build the client +RUN npm run build + +# Build the client for CDN and inject CDN fallback +# Conditional build logic for CDN assets +RUN if [ "$buildCdnAssets" = "true" ]; then \ + echo "Building client CDN assets..."; \ + npm run build-cdn --deploy-url $cdnUrl && \ + export sunbird_portal_cdn_url=$cdnUrl && \ + npm run inject-cdn-fallback && \ + echo "Completed client CDN prod build."; \ + else \ + echo "Skipping client CDN assets build."; \ + fi + +# Validate and copy CDN assets if they exist +RUN if [ "$buildCdnAssets" = "true" ]; then \ + echo "Validating and copying CDN assets..."; \ + if [ -d "src/app/dist-cdn" ] && [ "$(ls -A src/app/dist-cdn)" ]; then \ + mkdir -p /usr/src/app/cdn_assets && \ + cp -r src/app/dist-cdn/* /usr/src/app/cdn_assets/ && \ + echo "CDN assets copied successfully."; \ + else \ + echo "Directory src/app/dist-cdn does not exist or is empty. Skipping copy."; \ + fi; \ + else \ + echo "Skipping validation and copying of CDN assets."; \ + fi +# Set the working directory for server build +WORKDIR /usr/src/app + +# Copy package.json and yarn.lock for server +COPY src/app/package.json src/app/yarn.lock ./app_dist/ + +# Copy server-related files into the app_dist directory before installing dependencies +COPY src/app/libs ./app_dist/libs +COPY src/app/helpers ./app_dist/helpers +COPY src/app/proxy ./app_dist/proxy +COPY src/app/resourcebundles ./app_dist/resourcebundles +COPY src/app/framework.config.js ./app_dist/ +COPY src/app/sunbird-plugins ./app_dist/sunbird-plugins +COPY src/app/routes ./app_dist/routes +COPY src/app/constants ./app_dist/constants +COPY src/app/controllers ./app_dist/controllers +COPY src/app/server.js ./app_dist/ + +# Install server dependencies in the app_dist directory +WORKDIR /usr/src/app/app_dist +RUN yarn install --no-progress --frozen-lockfile --ignore-engines --production=true + +# Start a new stage for the final image FROM node:18.20.2-slim -RUN useradd -u 1001 -md /home/sunbird sunbird + +# Set the commit hash as a build argument and environment variable +ARG commit_hash="" +ENV commit_hash=${commit_hash} + +# Create a non-root user and group with specific UID and GID +RUN groupadd -g 1001 sunbird && \ + useradd -u 1001 -g sunbird -m -d /home/sunbird sunbird + +# Set the working directory and copy the built files WORKDIR /home/sunbird -COPY --chown=sunbird . /home/sunbird/app_dist/ +COPY --chown=sunbird:sunbird --from=builder /usr/src/app /home/sunbird + +# Switch to the non-root user USER sunbird + +# Rename the index.html file to index.ejs WORKDIR /home/sunbird/app_dist +RUN mv dist/index.html dist/index.ejs + +# Print the commit hash +RUN echo "Commit Hash: ${commit_hash}" + +# Add the build hash to package.json +RUN sed -i "/version/a\ \"buildHash\": \"${commit_hash}\"," package.json + +# Run the build script to perform additional tasks (e.g., phraseAppPull) +RUN node helpers/resourceBundles/build.js -task="phraseAppPull" + +# Expose the port used by the server EXPOSE 3000 -CMD ["node", "server.js", "&"] + +# Start the server +CMD ["node", "server.js"] \ No newline at end of file diff --git a/build.sh b/build.sh index db103e0cf17..d919990fe74 100644 --- a/build.sh +++ b/build.sh @@ -13,8 +13,10 @@ node=$2 org=$3 buildDockerImage=$4 buildCdnAssests=$5 +cdnUrl="" echo "buildDockerImage: " $buildDockerImage echo "buildCdnAssests: " $buildCdnAssests +## docker test start if [ $buildCdnAssests == true ] then cdnUrl=$6 @@ -22,84 +24,12 @@ then fi commit_hash=$(git rev-parse --short HEAD) -nvm install $NODE_VERSION # same is used in client and server - -cd src/app -mkdir -p app_dist/ # this folder should be created prior server and client build -rm -rf dist-cdn # remove cdn dist folder - -# function to run client build for docker image -build_client_docker(){ - echo "starting client local prod build" - npm run build # Angular prod build - echo "completed client local prod build" - cd .. - mv app_dist/dist/index.html app_dist/dist/index.ejs # rename index file -} -# function to run client build for cdn -build_client_cdn(){ - echo "starting client cdn prod build" - npm run build-cdn -- --deployUrl $cdnUrl # prod command - export sunbird_portal_cdn_url=$cdnUrl # required for inject-cdn-fallback task - npm run inject-cdn-fallback - echo "completed client cdn prod build" -} -# function to run client build -build_client(){ - echo "Building client in background" - nvm use $NODE_VERSION - npm rebuild canvas - cd client - echo "starting client yarn install" - yarn install --no-progress --production=true - echo "completed client yarn install" - if [ $buildDockerImage == true ] - then - build_client_docker & # run client local build in background - fi - if [ $buildCdnAssests == true ] - then - build_client_cdn & # run client local build in background - fi - wait # wait for both build to complete - echo "completed client post_build" -} - -# function to run server build -build_server(){ - echo "Building server in background" - echo "copying requied files to app_dist" - cp -R libs helpers proxy resourcebundles package.json framework.config.js sunbird-plugins routes constants controllers server.js ./../../Dockerfile app_dist - cd app_dist - nvm use $NODE_VERSION - echo "starting server yarn install" - yarn install --ignore-engines --no-progress --production=true - echo "completed server yarn install" - node helpers/resourceBundles/build.js -task="phraseAppPull" -} - -build_client & # run client build in background -if [ $buildDockerImage == true ] -then - build_server & # run client build in background -fi - -## wait for both build to complete -wait - -BUILD_ENDTIME=$(date +%s) -echo "Client and Server Build complete Took $[$BUILD_ENDTIME - $STARTTIME] seconds to complete." - -if [ $buildDockerImage == true ] -then -cd app_dist -sed -i "/version/a\ \"buildHash\": \"${commit_hash}\"," package.json echo "starting docker build" -docker build --no-cache --label commitHash=$(git rev-parse --short HEAD) -t ${org}/${name}:${build_tag} . +echo commit_hash $commit_hash +docker build --no-cache --build-arg buildCdnAssets=$buildCdnAssests --build-arg cdnUrl=$cdnUrl --build-arg commit_hash=$(git rev-parse --short HEAD) -t ${org}/${name}:${build_tag} . + echo "completed docker build" -cd ../../.. echo {\"image_name\" : \"${name}\", \"image_tag\" : \"${build_tag}\",\"commit_hash\" : \"${commit_hash}\", \"node_name\" : \"$node\"} > metadata.json -fi ENDTIME=$(date +%s) echo "build completed. Took $[$ENDTIME - $STARTTIME] seconds." \ No newline at end of file diff --git a/sonar-project.properties b/sonar-project.properties index 89c31e33386..c04b98f37c5 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,10 +1,7 @@ sonar.sources=src/app/client/src - sonar.exclusions=**/node_modules/**,**/environments/**,**/assets/**, **/*.module.ts, src/assets/**,src/app/client/src/assets/**,src/thidparty/**,src/app/modules/offline/**,src/app/client/src/**/*.spec.ts,src/app/client/src/**/*.spec.data.ts,src/app/client/src/**/*.module.ts,src/app/tenant/**,src/app/sunbird-plugins/**,src/app/assets/**, src/app/client/src/**/*.mock.data.ts, src/app/modules/cbse-program/**/**, src/app/plugins/profile/**/**, src/app/modules/core/services/tenant/**, src/app/plugins/profile/components/profile-page/profile-page.component.ts, src/app/modules/core/services/tenant/tenant.service.ts,src/app/modules/certificate/components/certificate-details/certificate-details.component.ts, src/app/modules/certificate/**/** - sonar.javascript.lcov.reportPaths=src/app/client/coverage/lcov.info - sonar.projectKey=Sunbird-Ed_SunbirdEd-portal sonar.host.url=https://sonarcloud.io sonar.organization=sunbird-ed