diff --git a/.github/workflows/4_pr_check.yml b/.github/workflows/4_pr_check.yml index ece3e842..e5a11083 100644 --- a/.github/workflows/4_pr_check.yml +++ b/.github/workflows/4_pr_check.yml @@ -12,6 +12,14 @@ on: - 'wazuh-agent/**' - '.github/**' +env: + ARTIFACTS_LOCAL_DIR: /home/runner/work/wazuh-docker/wazuh-docker/docker-images + ARTIFACT_NAMES: | + wazuh-manager.tar + wazuh-indexer.tar + wazuh-dashboard.tar + wazuh-agent.tar + jobs: build-docker-images: runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }} @@ -41,33 +49,17 @@ jobs: docker save wazuh/wazuh-dashboard:${{env.WAZUH_IMAGE_VERSION}} -o /home/runner/work/wazuh-docker/wazuh-docker/docker-images/wazuh-dashboard.tar docker save wazuh/wazuh-agent:${{env.WAZUH_IMAGE_VERSION}} -o /home/runner/work/wazuh-docker/wazuh-docker/docker-images/wazuh-agent.tar - - name: Temporarily save Wazuh manager Docker image - uses: actions/upload-artifact@v7 - with: - name: docker-artifact-manager - path: /home/runner/work/wazuh-docker/wazuh-docker/docker-images/wazuh-manager.tar - retention-days: 1 - - - name: Temporarily save Wazuh indexer Docker image - uses: actions/upload-artifact@v7 - with: - name: docker-artifact-indexer - path: /home/runner/work/wazuh-docker/wazuh-docker/docker-images/wazuh-indexer.tar - retention-days: 1 - - - name: Temporarily save Wazuh dashboard Docker image - uses: actions/upload-artifact@v7 - with: - name: docker-artifact-dashboard - path: /home/runner/work/wazuh-docker/wazuh-docker/docker-images/wazuh-dashboard.tar - retention-days: 1 - - - name: Temporarily save Wazuh agent Docker image - uses: actions/upload-artifact@v7 - with: - name: docker-artifact-agent - path: /home/runner/work/wazuh-docker/wazuh-docker/docker-images/wazuh-agent.tar - retention-days: 1 + - name: Temporarily save Wazuh Docker images + env: + S3_ARTIFACTS_PATH: ${{ secrets.CI_DEV_INTERNAL_S3_BUCKET }}/wazuh-docker/4_pr_check/${{ github.run_id }} + run: | + echo "Uploading Docker image artifacts to S3..." + while IFS= read -r artifact; do + [ -z "$artifact" ] && continue + echo " Uploading: $artifact" + aws s3 cp "${ARTIFACTS_LOCAL_DIR}/${artifact}" "${S3_ARTIFACTS_PATH}/${artifact}" + done <<< "$ARTIFACT_NAMES" + echo "All artifacts uploaded successfully." check-single-node: runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }} @@ -86,32 +78,21 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_PASSWORD }} - - name: Retrieve saved Wazuh indexer Docker image - uses: actions/download-artifact@v8 - with: - name: docker-artifact-indexer - - - name: Retrieve saved Wazuh manager Docker image - uses: actions/download-artifact@v8 - with: - name: docker-artifact-manager - - - name: Retrieve saved Wazuh dashboard Docker image - uses: actions/download-artifact@v8 - with: - name: docker-artifact-dashboard - - - name: Retrieve saved Wazuh agent Docker image - uses: actions/download-artifact@v8 - with: - name: docker-artifact-agent - - - name: Docker load + - name: Retrieve saved Wazuh Docker images and load them into Docker + env: + S3_ARTIFACTS_PATH: s3://${{ secrets.CI_DEV_INTERNAL_S3_BUCKET }}/wazuh-docker/4_pr_check/${{ github.run_id }} + ARTIFACTS_LOCAL_DIR: /home/runner/work/wazuh-docker/wazuh-docker/docker-images run: | - docker load --input ./wazuh-indexer.tar - docker load --input ./wazuh-dashboard.tar - docker load --input ./wazuh-manager.tar - docker load --input ./wazuh-agent.tar + mkdir -p "${ARTIFACTS_LOCAL_DIR}" + echo "Downloading and loading Docker image artifacts from S3..." + while IFS= read -r artifact; do + [ -z "$artifact" ] && continue + echo " Downloading: $artifact" + aws s3 cp "${S3_ARTIFACTS_PATH}/${artifact}" "${ARTIFACTS_LOCAL_DIR}/${artifact}" + echo " Loading into Docker: $artifact" + docker load -i "${ARTIFACTS_LOCAL_DIR}/${artifact}" + done <<< "$ARTIFACT_NAMES" + echo "All artifacts downloaded and loaded successfully." - name: Create single node certficates run: docker compose -f single-node/generate-indexer-certs.yml run --rm generator @@ -233,33 +214,21 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_PASSWORD }} - - name: Retrieve saved Wazuh dashboard Docker image - uses: actions/download-artifact@v8 - with: - name: docker-artifact-dashboard - - - name: Retrieve saved Wazuh manager Docker image - uses: actions/download-artifact@v8 - with: - name: docker-artifact-manager - - - name: Retrieve saved Wazuh indexer Docker image - uses: actions/download-artifact@v8 - with: - name: docker-artifact-indexer - - - name: Retrieve saved Wazuh agent Docker image - uses: actions/download-artifact@v8 - with: - name: docker-artifact-agent - - - name: Docker load + - name: Retrieve saved Wazuh Docker images and load them into Docker + env: + S3_ARTIFACTS_PATH: s3://${{ secrets.CI_DEV_INTERNAL_S3_BUCKET }}/wazuh-docker/4_pr_check/${{ github.run_id }} + ARTIFACTS_LOCAL_DIR: /home/runner/work/wazuh-docker/wazuh-docker/docker-images run: | - docker load --input ./wazuh-manager.tar - docker load --input ./wazuh-indexer.tar - docker load --input ./wazuh-dashboard.tar - docker load --input ./wazuh-agent.tar - rm -rf wazuh-manager.tar wazuh-indexer.tar wazuh-dashboard.tar wazuh-agent.tar + mkdir -p "${ARTIFACTS_LOCAL_DIR}" + echo "Downloading and loading Docker image artifacts from S3..." + while IFS= read -r artifact; do + [ -z "$artifact" ] && continue + echo " Downloading: $artifact" + aws s3 cp "${S3_ARTIFACTS_PATH}/${artifact}" "${ARTIFACTS_LOCAL_DIR}/${artifact}" + echo " Loading into Docker: $artifact" + docker load -i "${ARTIFACTS_LOCAL_DIR}/${artifact}" + done <<< "$ARTIFACT_NAMES" + echo "All artifacts downloaded and loaded successfully." - name: Create multi node certficates run: docker compose -f multi-node/generate-indexer-certs.yml run --rm generator diff --git a/.github/workflows/5_build_and_push_images.yml b/.github/workflows/5_build_and_push_images.yml index e6f2ce88..d6329abf 100644 --- a/.github/workflows/5_build_and_push_images.yml +++ b/.github/workflows/5_build_and_push_images.yml @@ -81,6 +81,8 @@ on: permissions: id-token: write contents: read +env: + LOCAL_ARTIFACT_URLS_FILEPATH: /tmp/${{ vars.ARTIFACT_URL_FILE_NAME }} jobs: setup: @@ -166,7 +168,6 @@ jobs: WORKFLOW_VENV: "${{ github.workspace }}/workflow_venv" GENERATE_PRESIGNED_URLS_SCRIPT_PATH: ${{ github.workspace }}/wazuh-automation/tools/sign_urls/generate_presigned_dev_urls.py PRESIGNED_URLS_SCRIPT_PROCESS: "build_docker" - LOCAL_ARTIFACT_URLS_FILEPATH: /tmp/${{ vars.ARTIFACT_URL_FILE_NAME }} COMMIT_LIST: ${{ inputs.commit_list }} ASSISTANT_REVISION: ${{ inputs.assistant_revision }} @@ -284,10 +285,9 @@ jobs: - name: Save presigned URLs file to artifact if: ${{ inputs.dev == true }} - uses: actions/upload-artifact@v4 - with: - name: presigned-artifact-urls-${{ github.run_id }} - path: ${{ env.LOCAL_ARTIFACT_URLS_FILEPATH }} + run: | + echo "Uploading presigned URLs artifact..." + aws s3 cp "${{ env.LOCAL_ARTIFACT_URLS_FILEPATH }}" "s3://${{ secrets.CI_DEV_INTERNAL_S3_BUCKET }}/wazuh-docker/5_build_and_push_images/${{ github.run_id }}/${{ vars.ARTIFACT_URL_FILE_NAME }}" build-and-push: runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }} @@ -337,10 +337,10 @@ jobs: - name: Download artifact_urls.yaml (dev) if: ${{ inputs.dev == true }} - uses: actions/download-artifact@v4 - with: - name: presigned-artifact-urls-${{ github.run_id }} - path: ./build-docker-images + run: | + echo "Downloading presigned URLs artifact..." + aws s3 cp "s3://${{ secrets.CI_DEV_INTERNAL_S3_BUCKET }}/wazuh-docker/5_build_and_push_images/${{ github.run_id }}/${{ vars.ARTIFACT_URL_FILE_NAME }}" "${{ env.LOCAL_ARTIFACT_URLS_FILEPATH }}" + mv "${{ env.LOCAL_ARTIFACT_URLS_FILEPATH }}" ./build-docker-images/${{ vars.ARTIFACT_URL_FILE_NAME }} - name: Compute component reference (dev) if: ${{ inputs.dev == true }} diff --git a/.github/workflows/5_bumper_repository.yml b/.github/workflows/5_bumper_repository.yml index ae1b3e63..281b4775 100644 --- a/.github/workflows/5_bumper_repository.yml +++ b/.github/workflows/5_bumper_repository.yml @@ -37,6 +37,11 @@ on: default: false required: false type: boolean + bump-issue-link: + description: 'Issue link used in the original bump (required for revert if different from issue-link)' + required: false + type: string + jobs: bump: name: Repository bumper 5.x @@ -96,18 +101,24 @@ jobs: version=${{ env.VERSION }} stage=${{ env.STAGE }} tag=${{ env.TAG }} - set_as_main=${{ inputs.set_as_main }} - if [[ "$set_as_main" == "true" ]]; then - script_params="--set-as-main" + if [[ -n "$version" && -n "$stage" && "$tag" != "true" ]]; then + script_params="--version ${version} --stage ${stage}" + elif [[ -n "$version" && -n "$stage" && "$tag" == "true" ]]; then + script_params="--version ${version} --stage ${stage} --tag" + elif [[ -z "$version" && -n "$stage" && "$tag" == "true" ]]; then + script_params="--stage ${stage} --tag" + elif [[ -z "$version" && -z "$stage" && "$tag" == "true" ]]; then + script_params="--tag" fi - # Both version and stage provided - if [[ -n "$version" && -n "$stage" && "$tag" != "true" ]]; then - script_params+=" --version ${version} --stage ${stage}" - elif [[ -n "$version" && -n "$stage" && "$tag" == "true" ]]; then - script_params+=" --version ${version} --stage ${stage} --tag ${tag}" + if [[ "$set_as_main" == "true" ]]; then + if [[ -z "$version" || -z "$stage" ]]; then + echo "Error: set_as_main requires both version and stage inputs." + exit 1 + fi + script_params="${script_params} --set-as-main" fi issue_number=$(echo "${{ inputs.issue-link }}" | awk -F'/' '{print $NF}') @@ -146,9 +157,18 @@ jobs: id: revert_step if: inputs.revert == true run: | + # 1. Get the current issue number (for the new revert branch/PR) ISSUE_NUMBER=$(echo "${{ inputs.issue-link }}" | awk -F'/' '{print $NF}') - BUMP_BRANCH="enhancement/wqa${ISSUE_NUMBER}-bump-${{ github.ref_name }}" + # 2. Get the issue number from the original bump (if provided; otherwise, defaults to the current one) + if [ -n "${{ inputs.bump-issue-link }}" ]; then + BUMP_ISSUE_NUMBER=$(echo "${{ inputs.bump-issue-link }}" | awk -F'/' '{print $NF}') + else + BUMP_ISSUE_NUMBER=$ISSUE_NUMBER + fi + + # 3. Search for the original bump branch using the obtained BUMP ISSUE number + BUMP_BRANCH="enhancement/wqa${BUMP_ISSUE_NUMBER}-bump-${{ github.ref_name }}" PR_NUMBER=$(gh pr list --head "$BUMP_BRANCH" --base "${{ github.ref_name }}" --state merged --json number --jq '.[0].number') @@ -167,7 +187,7 @@ jobs: # Remove the files to prevent them from being included in the revert commit git checkout HEAD -- VERSION.json 2>/dev/null || true git checkout HEAD -- CHANGELOG.md 2>/dev/null || true - # Add any other repository-specific version files here + # [!] ADD ANY OTHER REPOSITORY-SPECIFIC VERSION FILES HERE [!] if git diff --staged --quiet; then echo "No references to revert. Skipping commit." diff --git a/.github/workflows/5_check_integration_tools.yml b/.github/workflows/5_check_integration_tools.yml index 9fb4e6cd..b25b566b 100644 --- a/.github/workflows/5_check_integration_tools.yml +++ b/.github/workflows/5_check_integration_tools.yml @@ -53,6 +53,7 @@ env: AUTOMATION_REFERENCE: ${{ inputs.automation_reference || 'main' }} ALLOCATOR_PATH: /tmp/allocator_instance REGION: us-east-1 + LOGS_ARTIFACT_ZIP_FILE: "docker_logs_artifacts_${{ github.run_id }}.zip" jobs: # ------------------------------------------------------------------------- @@ -176,8 +177,8 @@ jobs: echo "deployment_matrix=[\"${DEPLOY_TYPE}\"]" >> $GITHUB_OUTPUT fi else - echo "pr_head_ref=${{ needs.get_pr_info.outputs.pr_head_ref }}" >> $GITHUB_OUTPUT - echo "deployment_matrix=${{ needs.get_pr_info.outputs.deployment_matrix }}" >> $GITHUB_OUTPUT + echo 'pr_head_ref=${{ needs.get_pr_info.outputs.pr_head_ref }}' >> $GITHUB_OUTPUT + echo 'deployment_matrix=${{ needs.get_pr_info.outputs.deployment_matrix }}' >> $GITHUB_OUTPUT fi - name: Checkout wazuh-docker PR branch (VERSION.json only) @@ -409,6 +410,7 @@ jobs: pip install -r wazuh-automation/deployability/deps/requirements.txt pip install -r wazuh-automation/integration-test-module/requirements.txt pip install -e wazuh-automation/integration-test-module/ + pip install pyyaml - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 @@ -417,6 +419,19 @@ jobs: role-session-name: docker-test-${{ github.run_id }}-${{ matrix.deployment_type }} aws-region: ${{ env.REGION }} + - name: Generate presigned cert tool URL + run: | + python wazuh-automation/tools/sign_urls/generate_presigned_dev_urls.py \ + --process build_docker \ + --wazuh-version "${{ env.DOCKER_VERSION }}" \ + --aws-s3-bucket-dev "${{ vars.AWS_S3_BUCKET_DEV }}" + + python3 -c " + import yaml + data = yaml.safe_load(open('/tmp/artifact_urls.yaml')) + print(f'wazuh_certs_tool={data[\"wazuh_certs_tool\"]}') + " >> "$GITHUB_ENV" + # ----------------------------------------------------------------------- # Provision: allocate VM and extract SSH credentials # ----------------------------------------------------------------------- @@ -502,20 +517,10 @@ jobs: - name: Prepare cert tool and config run: | DEPLOYMENT="${{ matrix.deployment_type }}" - VERSION="${{ env.WAZUH_VERSION }}" - STAGE="${{ env.WAZUH_STAGE }}" - MAJOR=$(echo "$VERSION" | cut -d. -f1) - echo "Cert tool: ${VERSION}-${STAGE} Docker image: ${{ env.DOCKER_TAG }}" + echo "Cert tool: ${{ env.wazuh_certs_tool }} Docker image: ${{ env.DOCKER_TAG }}" - # Download cert tool once on the runner - if [ -n "$STAGE" ]; then - CERT_TOOL_URL="https://packages-staging.xdrsiem.wazuh.info/pre-release/${MAJOR}.x/installation-assistant/wazuh-certs-tool-${VERSION}-${STAGE}.sh" - else - CERT_TOOL_URL="https://packages.wazuh.com/${MAJOR}.$(echo "$VERSION" | cut -d. -f2)/wazuh-certs-tool-${VERSION}-1.sh" - fi - echo "Downloading cert tool: $CERT_TOOL_URL" - curl -fsSL -o "wazuh-docker/${DEPLOYMENT}/wazuh-certs-tool.sh" "$CERT_TOOL_URL" + curl --output "wazuh-docker/${DEPLOYMENT}/wazuh-certs-tool.sh" "${{ env.wazuh_certs_tool }}" chmod +x "wazuh-docker/${DEPLOYMENT}/wazuh-certs-tool.sh" echo "Downloaded OK" @@ -732,11 +737,10 @@ jobs: - name: Upload Docker logs if: failure() || steps.run_tests.outcome == 'failure' - uses: actions/upload-artifact@v4 - with: - name: docker-logs-${{ matrix.deployment_type }}-${{ github.run_id }} - path: docker-logs-*.txt - retention-days: 7 + run: | + echo "Uploading Docker logs artifact..." + zip "${{ env.LOGS_ARTIFACT_ZIP_FILE }}" docker-logs-*.txt + aws s3 cp "${{ env.LOGS_ARTIFACT_ZIP_FILE }}" "s3://${{ secrets.CI_DEV_INTERNAL_S3_BUCKET }}/wazuh-docker/5_check_integration_tools/${{ github.run_id }}/${{ env.LOGS_ARTIFACT_ZIP_FILE }}" # ----------------------------------------------------------------------- # Reporting @@ -810,11 +814,16 @@ jobs: - name: Upload test results if: always() - uses: actions/upload-artifact@v4 - with: - name: test-results-docker-${{ matrix.deployment_type }}-${{ github.run_id }} - path: test-results-docker-${{ matrix.deployment_type }}.github - retention-days: 7 + env: + S3_ARTIFACTS_PATH: s3://${{ secrets.CI_DEV_INTERNAL_S3_BUCKET }}/wazuh-docker/5_check_integration_tools/${{ github.run_id }} + LOCAL_RESULTS_PATH: test-results-docker-${{ matrix.deployment_type }}.github + run: | + if [ -f "${LOCAL_RESULTS_PATH}" ]; then + echo "Uploading test results to S3..." + aws s3 cp "${LOCAL_RESULTS_PATH}" "${S3_ARTIFACTS_PATH}/test-results-docker-${{ matrix.deployment_type }}/" + else + echo "::warning::No test results file found - skipping upload (an earlier step likely failed before test_runner produced output)." + fi # ----------------------------------------------------------------------- # Cleanup: always stop stack and deallocate VM diff --git a/.github/workflows/5_pr_check.yml b/.github/workflows/5_pr_check.yml deleted file mode 100644 index c3c1eaea..00000000 --- a/.github/workflows/5_pr_check.yml +++ /dev/null @@ -1,664 +0,0 @@ -name: (5.x) Docker PR check -permissions: - contents: read - id-token: write -on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - branches: - - 5.* - - main - paths: - - 'build-docker-images/**' - - 'multi-node/**' - - 'single-node/**' - - 'wazuh-agent/**' - - '.github/**' - workflow_dispatch: - inputs: - docker_reference: - description: 'Branch or tag to build from' - required: true - type: string - -jobs: - - prepare-variables: - if: ${{ !github.event.pull_request.draft }} - runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }} - outputs: - WAZUH_VERSION: ${{ steps.dotenv.outputs.WAZUH_VERSION }} - WAZUH_IMAGE_VERSION: ${{ steps.dotenv.outputs.WAZUH_IMAGE_VERSION }} - WAZUH_REGISTRY: ${{ vars.IMAGE_REGISTRY_DEV }} - IMAGE_TAG: ${{ steps.dotenv.outputs.IMAGE_TAG }} - WAZUH_MINOR_VERSION: ${{ steps.dotenv.outputs.WAZUH_MINOR_VERSION }} - steps: - - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Export .env variables - id: dotenv - shell: bash - run: | - if [ ! -f .env ]; then echo "::error::.env missing"; exit 1; fi - grep -v '^#' .env | grep -v '^\s*$' >> "$GITHUB_OUTPUT" - FULL_VERSION=$(grep "^WAZUH_VERSION=" .env | cut -d'=' -f2) - MINOR_VERSION=$(echo "$FULL_VERSION" | cut -d'.' -f1,2) - echo "WAZUH_MINOR_VERSION=$MINOR_VERSION" >> "$GITHUB_OUTPUT" - - - build-images: - needs: prepare-variables - uses: ./.github/workflows/5_build_and_push_images.yml - secrets: inherit - with: - image_tag: ${{ needs.prepare-variables.outputs.WAZUH_IMAGE_VERSION }} - docker_reference: ${{ github.head_ref || inputs.docker_reference }} - wazuh_automation_reference: 'main' - commit_list: '["latest", "latest", "latest", "latest"]' - assistant_revision: 'latest' - id: ${{ github.run_id }} - dev: true - - Execute-Goss-tests: - needs: [prepare-variables, build-images] - runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }} - env: - WAZUH_IMAGE_VERSION: ${{ needs.prepare-variables.outputs.WAZUH_IMAGE_VERSION }} - WAZUH_REGISTRY: ${{ needs.prepare-variables.outputs.WAZUH_REGISTRY }} - steps: - - - name: Check out code - uses: actions/checkout@v4 - - - name: Install Goss - uses: e1himself/goss-installation-action@v1.0.3 - with: - version: 'v0.4.4' - - - name: Configure aws credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ secrets.AWS_IAM_DOCKER_ROLE }} - aws-region: "${{ secrets.AWS_REGION }}" - - - name: Log in to Amazon ECR - uses: aws-actions/amazon-ecr-login@v2 - - - name: Execute Goss tests (wazuh-manager) - run: dgoss run ${{ env.WAZUH_REGISTRY }}/wazuh/wazuh-manager:${{ env.WAZUH_IMAGE_VERSION }}-latest - env: - GOSS_SLEEP: 30 - GOSS_FILE: .github/.goss.yaml - - check-single-node: - name: Check single node on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: ["codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}", "codebuild-github-actions-codebuild-runner-devops-arm-${{ github.run_id }}-${{ github.run_attempt }}"] - fail-fast: false - needs: [prepare-variables, Execute-Goss-tests] - env: - WAZUH_IMAGE_VERSION: ${{ needs.prepare-variables.outputs.WAZUH_IMAGE_VERSION }} - WAZUH_MINOR_VERSION: ${{ needs.prepare-variables.outputs.WAZUH_MINOR_VERSION }} - WAZUH_REGISTRY: ${{ needs.prepare-variables.outputs.WAZUH_REGISTRY }} - INDEXER_USERNAME: admin - INDEXER_PASSWORD: admin - MANAGER_NODES: "manager" - API_USERNAME: wazuh-wui - API_PASSWORD: wazuh-wui - steps: - - - name: Check out code - uses: actions/checkout@v4 - - - name: Configure aws credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ secrets.AWS_IAM_DOCKER_ROLE }} - aws-region: "${{ secrets.AWS_REGION }}" - - - name: Log in to Amazon ECR - uses: aws-actions/amazon-ecr-login@v2 - - - name: Download artifact_urls.yaml - uses: actions/download-artifact@v4 - with: - name: presigned-artifact-urls-${{ github.run_id }} - path: ./single-node/ - - - name: Log in to Docker Hub - uses: docker/login-action@v4 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_PASSWORD }} - - - name: Add environment variables into GITHUB_ENV - run: | - # Export variables to the environment - awk -F':' '!/^#/ && NF>1 {name=$1; val=substr($0,length(name)+3); gsub(/[-.]/,"_",name); print name "=" val}' ${{ vars.ARTIFACT_URL_FILE_NAME }} >> "$GITHUB_ENV" - working-directory: ./single-node/ - - - name: Create single node certficates - run: | - curl --output ./wazuh-certs-tool.sh "${{ env.wazuh_certs_tool }}" - cat > config.yml </$(ip addr show docker0 | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1)/g" wazuh-agent/docker-compose.yml - - - name: Edit Wazuh agent docker-compose file - if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }} - shell: bash - env: - WAZUH_REGISTRY: ${{ env.WAZUH_REGISTRY }} - run: | - TARGET_FILE="wazuh-agent/docker-compose.yml" - if [ -f "$TARGET_FILE" ]; then - echo "Updating registry in $TARGET_FILE to: ${{ env.WAZUH_REGISTRY }}" - sed -i "s|wazuh/wazuh-|${{ env.WAZUH_REGISTRY }}/wazuh/wazuh-|g" "$TARGET_FILE" - sed -i "s/\(.*wazuh\/wazuh-.*:\)${{ env.WAZUH_IMAGE_VERSION }}/\1${{ env.WAZUH_IMAGE_VERSION }}-latest/g" "$TARGET_FILE" - else - echo "File $TARGET_FILE not found" - exit 1 - fi - - - name: Start Wazuh agent - if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }} - run: docker compose up -d - working-directory: ./wazuh-agent - - - name: Check Wazuh agent enrollment - if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }} - run: | - enrolled=false - for i in {1..5}; do - TOKEN=$(curl -s -u ${{ env.API_USERNAME }}:${{ env.API_PASSWORD }} -k -X POST "https://127.0.0.1:55000/security/user/authenticate?raw=true") - agents="`curl -k -s -X GET "https://127.0.0.1:55000/agents?pretty=true" -H "Authorization: Bearer ${TOKEN}" | jq -r .data.affected_items | grep active | wc -l`" - if [[ $agents -gt 0 ]]; then - echo "Wazuh agents: ${agents}" - echo "OK" - enrolled=true - break - else - curl -k -s -X GET "https://127.0.0.1:55000/agents?pretty=true" -H "Authorization: Bearer ${TOKEN}" - echo "Wazuh agents: ${agents}. Retrying in 10s" - [ $i -lt 5 ] && sleep 10 - fi - done - if [[ "$enrolled" != "true" ]]; then - echo "Error: Wazuh agent enrollment did not reach expected active agents threshold" - exit 1 - fi - - - name: Check errors in wazuh-manager.log for Wazuh manager - if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }} - run: ./.github/single-node-log-check.sh - - - name: Check documents into wazuh-states index - if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }} - run: | - for i in {1..20}; do - echo "Checking documents in wazuh-states (Attempt $i/20)..." - RESPONSE=$(curl -XGET "https://127.0.0.1:9200/wazuh-states*/_count" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s || echo "{}") - DOCS=$(echo "$RESPONSE" | jq -r '.count // 0') - if [[ "$DOCS" -gt 0 ]]; then - echo "wazuh-states index has documents: ${DOCS}" - exit 0 - fi - echo "The index is empty or does not exist yet (Count: $DOCS). Waiting 60s" - [ $i -lt 20 ] && sleep 60 - done - echo "Error: No documents found in wazuh-states after 20 attempts." - echo "Last response: $RESPONSE" - exit 1 - - - name: Docker logs - if: always() - continue-on-error: true - run: | - INDEXER_CONTAINERS=$(docker ps --format '{{.Names}}') - for CONTAINER_NAME in $INDEXER_CONTAINERS; do - echo "" - echo "=========================================================" - echo "Container logs for $CONTAINER_NAME" - echo "=========================================================" - docker logs "$CONTAINER_NAME" - echo "---------------------------------------------------------" - done - working-directory: ./single-node - - check-multi-node: - name: Check multi node on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: ["codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}", "codebuild-github-actions-codebuild-runner-devops-arm-${{ github.run_id }}-${{ github.run_attempt }}"] - fail-fast: false - needs: [prepare-variables, Execute-Goss-tests] - env: - WAZUH_IMAGE_VERSION: ${{ needs.prepare-variables.outputs.WAZUH_IMAGE_VERSION }} - WAZUH_MINOR_VERSION: ${{ needs.prepare-variables.outputs.WAZUH_MINOR_VERSION }} - WAZUH_REGISTRY: ${{ needs.prepare-variables.outputs.WAZUH_REGISTRY }} - INDEXER_USERNAME: admin - INDEXER_PASSWORD: admin - MANAGER_NODES: "master,worker01" - API_USERNAME: wazuh-wui - API_PASSWORD: wazuh-wui - steps: - - - name: Check out code - uses: actions/checkout@v4 - - - name: Configure aws credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ secrets.AWS_IAM_DOCKER_ROLE }} - aws-region: "${{ secrets.AWS_REGION }}" - - - name: Log in to Amazon ECR - uses: aws-actions/amazon-ecr-login@v2 - - - name: Download artifact_urls.yaml - uses: actions/download-artifact@v4 - with: - name: presigned-artifact-urls-${{ github.run_id }} - path: ./multi-node/ - - - name: Log in to Docker Hub - uses: docker/login-action@v4 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_PASSWORD }} - - - name: Add environment variables into GITHUB_ENV - run: | - # Export variables to the environment - awk -F':' '!/^#/ && NF>1 {name=$1; val=substr($0,length(name)+3); gsub(/[-.]/,"_",name); print name "=" val}' ${{ vars.ARTIFACT_URL_FILE_NAME }} >> "$GITHUB_ENV" - working-directory: ./multi-node/ - - - name: Create multi node certficates - run: | - curl --output ./wazuh-certs-tool.sh "${{ env.wazuh_certs_tool }}" - cat > config.yml </$(ip addr show docker0 | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1)/g" wazuh-agent/docker-compose.yml - - - name: Edit Wazuh agent docker-compose file - if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }} - shell: bash - env: - WAZUH_REGISTRY: ${{ env.WAZUH_REGISTRY }} - run: | - TARGET_FILE="wazuh-agent/docker-compose.yml" - if [ -f "$TARGET_FILE" ]; then - echo "Updating registry in $TARGET_FILE to: ${{ env.WAZUH_REGISTRY }}" - sed -i "s|wazuh/wazuh-|${{ env.WAZUH_REGISTRY }}/wazuh/wazuh-|g" "$TARGET_FILE" - sed -i "s/\(.*wazuh\/wazuh-.*:\)${{ env.WAZUH_IMAGE_VERSION }}/\1${{ env.WAZUH_IMAGE_VERSION }}-latest/g" "$TARGET_FILE" - else - echo "File $TARGET_FILE not found" - exit 1 - fi - - - name: Start Wazuh agent - if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }} - run: docker compose -f wazuh-agent/docker-compose.yml up -d - - - name: Check Wazuh agent enrollment - if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }} - run: | - enrolled=false - for i in {1..5}; do - TOKEN=$(curl -s -u ${{ env.API_USERNAME }}:${{ env.API_PASSWORD }} -k -X POST "https://127.0.0.1:55000/security/user/authenticate?raw=true") - agents="`curl -k -s -X GET "https://127.0.0.1:55000/agents?pretty=true" -H "Authorization: Bearer ${TOKEN}" | jq -r .data.affected_items | grep active | wc -l`" - if [[ $agents -gt 0 ]]; then - echo "Wazuh agents: ${agents}" - echo "OK" - enrolled=true - break - else - curl -k -s -X GET "https://127.0.0.1:55000/agents?pretty=true" -H "Authorization: Bearer ${TOKEN}" - echo "Wazuh agents: ${agents}. Retrying in 10s" - [ $i -lt 5 ] && sleep 10 - fi - done - if [[ "$enrolled" != "true" ]]; then - echo "Error: Wazuh agent enrollment did not reach expected active agents threshold" - exit 1 - fi - - - name: Check errors in wazuh-manager.log for Wazuh manager - if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }} - run: ./.github/multi-node-log-check.sh - - - name: Check documents into wazuh-states index - if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }} - run: | - for i in {1..20}; do - echo "Checking documents in wazuh-states (Attempt $i/20)..." - RESPONSE=$(curl -XGET "https://127.0.0.1:9200/wazuh-states*/_count" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s || echo "{}") - DOCS=$(echo "$RESPONSE" | jq -r '.count // 0') - if [[ "$DOCS" -gt 0 ]]; then - echo "wazuh-states index has documents: ${DOCS}" - exit 0 - fi - echo "The index is empty or does not exist yet (Count: $DOCS). Waiting 60s" - [ $i -lt 20 ] && sleep 60 - done - echo "Error: No documents found in wazuh-states after 20 attempts." - echo "Last response: $RESPONSE" - exit 1 - - - name: Docker logs - if: always() - continue-on-error: true - run: | - INDEXER_CONTAINERS=$(docker ps --format '{{.Names}}') - for CONTAINER_NAME in $INDEXER_CONTAINERS; do - echo "" - echo "=========================================================" - echo "Container logs for $CONTAINER_NAME" - echo "=========================================================" - docker logs "$CONTAINER_NAME" - echo "---------------------------------------------------------" - done - working-directory: ./multi-node diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 28e0a483..312b8d86 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -30,3 +30,9 @@ - [Security](ref/security.md) - [Performance](ref/performance.md) - [Glossary](ref/glossary.md) + +--- + +# Integration Tests + +- [Docker Integration Tests](ref/integration_test/docker_integration_tests.md) diff --git a/docs/ref/integration_test/docker_integration_tests.md b/docs/ref/integration_test/docker_integration_tests.md new file mode 100644 index 00000000..23ea2e76 --- /dev/null +++ b/docs/ref/integration_test/docker_integration_tests.md @@ -0,0 +1,332 @@ +# Docker Integration Tests + +Workflow file: `.github/workflows/5_check_integration_tools.yml` + +This workflow optionally builds Docker images from the PR branch, provisions a dedicated AWS VM, deploys the Wazuh Docker stack (single-node or multi-node), and runs the integration test suite against it via SSH. + +--- + +## Triggers + +| Mode | Trigger | Who can trigger | +|---|---|---| +| PR comment | `issue_comment` on an open, non-draft PR | Any repo collaborator | +| Manual | `workflow_dispatch` | Anyone with repo write access | + +--- + +## Execution Flows + +### issue_comment flow + +```mermaid +flowchart TD + A[PR comment posted] --> B{Recognized command\non open non-draft PR?} + B -- No --> Z[Ignored] + B -- Yes --> C[get_pr_info\nReact · Extract PR data\nParse command · Create Check Run] + C --> D[prepare\nResolve branch · Read VERSION.json] + D --> E[build_images\nBuild + push to ECR\nalways runs on PR comment] + E --> F{deployment_matrix} + F --> G[docker_test\nsingle-node] + F --> H[docker_test\nmulti-node] + G --> I[update_check] + H --> I +``` + +**Recognized commands:** + +| Comment | Deployment matrix | +|---|---| +| `/test-docker` | `["single-node","multi-node"]` | +| `/test-docker-single` | `["single-node"]` | +| `/test-docker-multi` | `["multi-node"]` | + +When triggered by PR comment, `build_images` **always** runs — images are always built from the PR branch and pushed to ECR. + +### workflow_dispatch flow + +```mermaid +flowchart TD + A[Manual trigger] --> D[prepare\nResolve branch · Read VERSION.json] + D --> E{Build needed?\nno version + no stage\n+ registry=ECR} + E -- Yes --> F[build_images\nBuild + push to ECR] + E -- No --> G{deployment_type input} + F --> G + G -- single-node --> H[docker_test\nsingle-node] + G -- multi-node --> I[docker_test\nmulti-node] + G -- both --> H & I +``` + +`build_images` is **skipped** when either `version` or `stage` is provided, or when `registry = DockerHub`. + +--- + +## Parameters + +### workflow_dispatch inputs + +| Input | Required | Default | Description | +|---|---|---|---| +| `pr_head_ref` | Yes | — | Branch of `wazuh-docker` to test | +| `automation_reference` | No | `main` | Branch of `wazuh-automation` to use | +| `deployment_type` | Yes | — | `single-node`, `multi-node`, or `both` | +| `version` | No | — | Override image version (e.g. `5.0.1`). If empty, reads from `VERSION.json` | +| `stage` | No | — | Image stage suffix (e.g. `beta1`, `beta2-latest`). Required when `version` is set | +| `registry` | No | `ECR` | `ECR` (dev/built images) or `DockerHub` (released images) | + +### issue_comment parameters + +All parameters are derived automatically: + +| Parameter | Source | +|---|---| +| `pr_head_ref` | PR head branch from GitHub API | +| `deployment_matrix` | Parsed from comment command | +| `version` / `stage` | Read from `VERSION.json` on the PR branch | +| `registry` | Always ECR (images are always built) | +| `automation_reference` | Always `main` | + +--- + +## Image Resolution Scenarios + +The workflow distinguishes five cases based on inputs: + +| Case | `version` input | `stage` input | Registry | Action | Image tag | +|---|---|---|---|---|---| +| a.1 | empty | empty | ECR (or PR comment) | **BUILD** from PR → ECR | `{version}-{stage}-latest` | +| a.2 | empty | empty | DockerHub | Pull (no build) | `{version}-{stage}` | +| b.1 | set | empty | ECR | Pull (no build) | `{version}-latest` | +| b.2 | set | empty | DockerHub | Pull (no build) | `{version}` | +| c | set or empty | set | ECR or DockerHub | Pull (no build) | `{version}-{stage}` | + +> When neither `version` nor `stage` is set, `version` and `stage` are read from `VERSION.json` on the target branch. + +> Case a.1 always applies when triggered by PR comment, regardless of the `registry` input (which is not available in that trigger mode). + +--- + +## Job Details + +### Job 1 — `get_pr_info` (issue_comment only) + +| Step | What it does | +|---|---| +| React to comment | Adds a 🚀 reaction to the triggering PR comment | +| Extract PR data | Calls GitHub API to get PR `head_ref` and `head_sha` | +| Parse command | Maps comment text → `deployment_matrix` JSON and `check_name` string | +| Create Check Run | Creates a GitHub Check Run in `in_progress` state on the PR head SHA | + +### Job 2 — `prepare` (both triggers) + +| Step | What it does | +|---|---| +| Resolve context | Reads inputs (workflow_dispatch) or `get_pr_info` outputs (issue_comment) | +| Checkout `VERSION.json` | Sparse-checks out only `VERSION.json` from the target branch | +| Read version info | Extracts `version` and `stage` from `VERSION.json` | +| Show test plan | Logs the resolved image case (a.1/a.2/b.1/b.2/c) and writes a summary table | + +Outputs: `pr_head_ref`, `deployment_matrix`, `wazuh_version`, `wazuh_stage`. + +### Job 3 — `build_images` (conditional) + +Calls the reusable workflow `.github/workflows/5_build_and_push_images.yml`. + +**Runs when:** `version == ''` AND `stage == ''` AND (`registry == 'ECR'` OR `github.event_name == 'issue_comment'`). + +**Skipped when:** any explicit `version` or `stage` is provided, or `registry = DockerHub`. + +| Parameter passed | Value | +|---|---| +| `image_tag` | `{wazuh_version}-{wazuh_stage}` | +| `docker_reference` | `pr_head_ref` | +| `wazuh_automation_reference` | `automation_reference` input | +| `products` | `wazuh-manager,wazuh-dashboard,wazuh-indexer,wazuh-agent` | +| `dev` | `true` | +| `id` | `docker-integration-{run_id}` | + +### Job 4 — `docker_test` (matrix, both triggers) + +Runs once per entry in `deployment_matrix`. Each instance provisions its own VM. + +#### Setup + +1. Checkout `wazuh-automation` at `automation_reference` +2. Checkout `wazuh-docker` at `pr_head_ref` +3. Resolve image configuration (see [Image Resolution Scenarios](#image-resolution-scenarios)) → sets `DOCKER_REGISTRY`, `DOCKER_TAG`, `DOCKER_VERSION` +4. Set up Python 3.12 and install `test_runner` +5. Configure AWS credentials via OIDC (`AWS_IAM_DOCKER_ROLE`) + +#### Instance allocation + +Provisions a dedicated AWS VM using the `deployability` allocator module: + +```bash +python3 wazuh-automation/deployability/modules/allocation/main.py \ + --action create \ + --provider aws \ + --size large \ + --composite-name ubuntu-24-amd64 \ + --instance-name gha_{run_id}_docker_{deployment_type} \ + --label-team devops \ + --label-termination-date 1d +``` + +The allocator writes `inventory.yml` with the SSH connection details (`ansible_host`, `ansible_port`, `ansible_user`, `ansible_ssh_private_key_file`). These are extracted and exported as `SSH_HOST`, `SSH_PORT`, `SSH_USER`, `SSH_KEY` environment variables. + +#### VM configuration and Docker install + +All subsequent steps run on the remote VM over SSH: + +1. **Install Docker CE**: `curl -fsSL https://get.docker.com | sudo sh` +2. **Login to ECR** (when registry is ECR or trigger is issue_comment): authenticates the VM's Docker daemon to the dev registry +3. **Set `vm.max_map_count=262144`**: required for OpenSearch/Wazuh Indexer + +#### Certificate generation and config + +Runs on the **runner** (not the VM): + +1. **Download `wazuh-certs-tool.sh`** directly from the packages URL: + - Pre-release: `packages-staging.xdrsiem.wazuh.info/pre-release/{major}.x/installation-assistant/wazuh-certs-tool-{version}-{stage}.sh` + - Release: `packages.wazuh.com/{major}.{minor}/wazuh-certs-tool-{version}-1.sh` + +2. **Generate `config.yml`** inline based on deployment type: + + **single-node:** + ```yaml + nodes: + indexer: [{ name: wazuh.indexer, dns: wazuh.indexer }] + manager: [{ name: wazuh.manager, dns: wazuh.manager }] + dashboard:[{ name: wazuh.dashboard, dns: wazuh.dashboard }] + ``` + + **multi-node:** + ```yaml + nodes: + indexer: + - { name: wazuh1.indexer, dns: wazuh1.indexer } + - { name: wazuh2.indexer, dns: wazuh2.indexer } + - { name: wazuh3.indexer, dns: wazuh3.indexer } + manager: + - { name: wazuh.master, dns: wazuh.master, node_type: master } + - { name: wazuh.worker, dns: wazuh.worker, node_type: worker } + dashboard: [{ name: wazuh.dashboard, dns: wazuh.dashboard }] + ``` + +3. **Copy `wazuh-docker/` to VM** via SCP: `scp -r wazuh-docker {remote}:/tmp/wazuh-docker` + +4. **Generate certificates on VM**: runs `tools/utils/deployment/certificates-conf.sh --cert --copy` inside `/tmp/wazuh-docker/{deployment}/` + +#### Deployment + +```bash +# On the VM +cd /tmp/wazuh-docker/{deployment_type} +sudo docker compose up -d +``` + +Waits up to **15 minutes** polling every 10 seconds until all non-nginx containers report `healthy` status. + +After containers are healthy, waits for steady state: +- `single-node`: 60 seconds +- `multi-node`: 90 seconds + +#### Test execution + +```bash +test_runner \ + --test-type "docker-{deployment_type}" \ + --deployment-type "docker-{deployment_type}" \ + --ssh-host "{SSH_HOST}" \ + --ssh-port "{SSH_PORT}" \ + --ssh-key-path "{SSH_KEY}" \ + --ssh-username "{SSH_USER}" \ + --version "{DOCKER_VERSION}" \ + --log-level INFO \ + --output github \ + --output-file "test-results-docker-{deployment_type}.github" +``` + +| Argument | Value | Notes | +|---|---|---| +| `--test-type` | `docker-single-node` or `docker-multi-node` | Selects the test module set | +| `--deployment-type` | `docker-single-node` or `docker-multi-node` | Selects the deployment profile | +| `--ssh-host/port/key/username` | From allocator inventory | Connects to the allocated VM | +| `--version` | Resolved `DOCKER_VERSION` | Used for version assertion tests | +| `--output github` | — | Emits GitHub Actions annotations | + +For details on what `docker-single-node` and `docker-multi-node` test types validate, see the `Integration Test Module — Description` of the internal documentation. + +#### Reporting + +| Output | When | Content | +|---|---|---| +| Step summary | Always | Test results appended to `$GITHUB_STEP_SUMMARY` | +| PR comment | `issue_comment` trigger only | Posts or updates a comment (marker: ``) with ✅/❌ and results | +| Artifact: `test-results-docker-{deployment}-{run_id}` | Always | Results file, retained 7 days | +| Artifact: `docker-logs-{deployment}-{run_id}` | On failure only | Full `docker compose logs` output, retained 7 days | + +#### Cleanup (always runs, even on failure) + +1. `docker compose down -v` on the VM (stops containers and removes volumes) +2. Deallocate the VM: + ```bash + python3 wazuh-automation/deployability/modules/allocation/main.py \ + --action delete \ + --track-output {ALLOCATOR_PATH}/track.yml + ``` + +### Job 5 — `update_check` (issue_comment only) + +Updates the GitHub Check Run created in Job 1: + +| `docker_test` result | Check conclusion | +|---|---| +| `success` | `success` — ✅ All Docker integration tests passed | +| `failure` | `failure` — ❌ One or more tests failed | +| `cancelled` | `cancelled` | + +--- + +## Required Secrets and Variables + +### Secrets + +| Secret | Used by | +|---|---| +| `AWS_IAM_DOCKER_ROLE` | OIDC role for AWS operations (allocator + ECR) | +| `GH_CLONE_TOKEN` | Checkout `wazuh-automation` | +| `GITHUB_TOKEN` | PR comments and Check Run updates (built-in) | + +### Repository variables + +| Variable | Used by | +|---|---| +| `IMAGE_REGISTRY_PROD` | DockerHub registry URL | +| `IMAGE_REGISTRY_DEV` | ECR registry URL | + +--- + +## Permissions + +| Permission | Purpose | +|---|---| +| `id-token: write` | OIDC authentication to AWS | +| `contents: read` | Checkout repository | +| `pull-requests: write` | Post PR comments | +| `issues: write` | Post comments via issues API | +| `checks: write` | Create and update GitHub Check Runs | + +--- + +## Instance Naming + +Allocated VMs are named: + +``` +gha_{github.run_id}_docker_{deployment_type} +``` + +Example: `gha_12345678_docker_single-node` + +VMs are tagged with `termination-date: 1d` — they are automatically terminated after 24 hours as a safety net, even if the cleanup step fails. diff --git a/tools/repository_bumper.sh b/tools/repository_bumper.sh index 4712761a..6c8d2be9 100644 --- a/tools/repository_bumper.sh +++ b/tools/repository_bumper.sh @@ -9,6 +9,8 @@ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" LOG_FILE="${DIR}/tools/repository_bumper_$(date +"%Y-%m-%d_%H-%M-%S-%3N").log" VERSION="" STAGE="" +TAG="" +REFERENCE="" FILES_EDITED=() FILES_EXCLUDED='--exclude="repository_bumper_*.log" --exclude="CHANGELOG.md" --exclude="repository_bumper.sh" --exclude="*_bumper_repository.yml" --exclude="mermaid-init.js" --exclude="mermaid.min.js"' @@ -74,40 +76,44 @@ update_stage_in_files() { FILES_EDITED+=("${file}") fi done +} - if [ $STAGE != "alpha0" ]; then - version_tag_string=": 'v${VERSION}'" - files_tag=( $(grep_command "${version_tag_string}" "${DIR}") ) - for file in "${files_tag[@]}"; do - sed -i -E "s/(: )'v${VERSION}'/\1'v${VERSION}-${STAGE}'/g" "${file}" - if [[ $(git diff --name-only "${file}") ]]; then - FILES_EDITED+=("${file}") - fi - done - - version_number_string=": '${VERSION}'" - files_version=( $(grep -RlE ": '[0-9]\.[0-9]+\.[0-9]+'" "${DIR}") ) - for file in "${files_version[@]}"; do - sed -i -E "s/(: )'${VERSION}'/\1'v${VERSION}-${STAGE}'/g" "${file}" - if [[ $(git diff --name-only "${file}") ]]; then - FILES_EDITED+=("${file}") - fi - done +# Compute the value written into branch reference defaults (": '...'"). +# Without --tag, references stay branch-like (e.g. 5.0.0). +# With --tag, references become tag-like (e.g. v5.0.0-beta3), or a plain release +# tag (e.g. v5.0.0) when no stage is provided. +build_reference() { + if [[ -n "$TAG" ]]; then + if [[ -z "$STAGE" ]]; then + REFERENCE="v${VERSION}" + else + REFERENCE="v${VERSION}-${STAGE}" + fi + else + REFERENCE="${VERSION}" fi } +# Tag mode only: normalize every reference to the current version +# (branch-like "5.0.0", "v5.0.0" or "v5.0.0-") into ${REFERENCE}. +# Matching is restricted to ": '...'" entries so plain version strings +# elsewhere in the repository are left untouched. +update_tag_references() { + local V_ESC="${VERSION//./\\.}" + files=( $(grep_command "${VERSION}" "${DIR}") ) + for file in "${files[@]}"; do + sed -Ei "s/(:[[:space:]]*')v?${V_ESC}(-[A-Za-z0-9]+)?(')/\1${REFERENCE}\3/g" "${file}" + if [[ $(git diff --name-only "${file}") ]]; then + FILES_EDITED+=("${file}") + fi + done +} + update_main_in_files() { - if [[ $STAGE == "alpha0" ]]; then - bump_value="${VERSION}" - else - bump_value="v${VERSION}" - fi - main_string=": 'main'" + local main_string=": 'main'" files=( $(grep_command "${main_string}" "${DIR}") ) for file in "${files[@]}"; do - if [[ "$skip_urls" != "yes" ]]; then - sed -Ei "s/(:[[:space:]])'main'/\1'${bump_value}'/g" "${file}" - fi + sed -Ei "s/(:[[:space:]])'main'/\1'${REFERENCE}'/g" "${file}" if [[ $(git diff --name-only "${file}") ]]; then FILES_EDITED+=("${file}") fi @@ -141,8 +147,8 @@ main() { shift 2 ;; --tag) - TAG="$2" - shift 2 + TAG="yes" + shift 1 ;; --set-as-main) set_as_main="yes" @@ -155,15 +161,33 @@ main() { esac done - # Validate arguments - if [[ -z "${VERSION}" ]]; then - echo "Error: --version argument is required." | tee -a "${LOG_FILE}" + # --tag rewrites branch references into tag-like references (e.g. v5.0.0-beta3) + # and re-tags the Docker images accordingly. It is mutually exclusive with + # --set-as-main, which keeps references on main. + if [[ -n "$TAG" && -n "$set_as_main" ]]; then + echo "Error: --tag cannot be combined with --set-as-main." | tee -a "${LOG_FILE}" exit 1 fi - if [[ -z "${STAGE}" ]]; then - echo "Error: --stage argument is required." | tee -a "${LOG_FILE}" - exit 1 + # Read the current version/stage early: tag scenarios may omit --version and/or + # --stage and reuse the values already stored in VERSION.json. + get_old_version_and_stage + + # Resolve and validate arguments depending on the mode + if [[ -n "$TAG" ]]; then + # Tag mode: version defaults to the current one; stage is optional + # (absent yields a release tag without a stage suffix). + [[ -z "$VERSION" ]] && VERSION="$OLD_VERSION" + else + # Branch mode: a full version + stage bump is required + if [[ -z "${VERSION}" ]]; then + echo "Error: --version argument is required." | tee -a "${LOG_FILE}" + exit 1 + fi + if [[ -z "${STAGE}" ]]; then + echo "Error: --stage argument is required." | tee -a "${LOG_FILE}" + exit 1 + fi fi # Validate if version is in the correct format @@ -172,28 +196,25 @@ main() { exit 1 fi - # Validate if stage is in the correct format - STAGE=$(echo "${STAGE}" | tr '[:upper:]' '[:lower:]') - if ! [[ "${STAGE}" =~ ^(alpha[0-9]*|beta[0-9]*|rc[0-9]*|stable)$ ]]; then - echo "Error: Stage must be one of the following examples: alpha1, beta1, rc1, stable." | tee -a "${LOG_FILE}" - exit 1 + # Validate if stage is in the correct format (when provided) + if [[ -n "${STAGE}" ]]; then + STAGE=$(echo "${STAGE}" | tr '[:upper:]' '[:lower:]') + if ! [[ "${STAGE}" =~ ^(alpha[0-9]*|beta[0-9]*|rc[0-9]*|stable)$ ]]; then + echo "Error: Stage must be one of the following examples: alpha1, beta1, rc1, stable." | tee -a "${LOG_FILE}" + exit 1 + fi fi - # Set skip_urls variable based on set_as_main flag + # Compute the value written into branch reference defaults + build_reference + echo "Reference for branch defaults: ${REFERENCE}" | tee -a "${LOG_FILE}" + + # Convert 'main' references unless they must keep pointing to main (set-as-main) if [[ -z "$set_as_main" ]]; then - echo "Updating version from main to $VERSION" | tee -a "${LOG_FILE}" - update_main_in_files "$VERSION" "$STAGE" + echo "Updating 'main' references to ${REFERENCE}" | tee -a "${LOG_FILE}" + update_main_in_files fi - # Validate if tag is true or false - if [[ -n "${TAG}" && ! "${TAG}" =~ ^(true|false)$ ]]; then - echo "Error: --tag must be either true or false." | tee -a "${LOG_FILE}" - exit 1 - fi - - # Get old version and stage - get_old_version_and_stage - if [[ "${OLD_VERSION}" != "${VERSION}" ]]; then echo "Updating version from ${OLD_VERSION} to ${VERSION}" | tee -a "${LOG_FILE}" update_version_in_files "${VERSION}" @@ -203,10 +224,13 @@ main() { update_stage_in_files "$VERSION" "$STAGE" fi - # Update Docker images tag if tag is true - if [[ "${TAG}" == "true" ]]; then - echo "Updating Docker images tag to ${VERSION}-${STAGE}" | tee -a "${LOG_FILE}" - update_docker_images_tag "${VERSION}-${STAGE}" + # Tag mode: normalize remaining version references and re-tag the Docker images + # (image tags carry no leading 'v', e.g. 5.0.0-beta3). + if [[ -n "$TAG" ]]; then + echo "Updating version references to tag reference ${REFERENCE}" | tee -a "${LOG_FILE}" + update_tag_references + echo "Updating Docker images tag to ${REFERENCE#v}" | tee -a "${LOG_FILE}" + update_docker_images_tag "${REFERENCE#v}" fi