diff --git a/.github/actions/docker-login/action.yml b/.github/actions/docker-login/action.yml new file mode 100644 index 0000000000..b9e6d079c2 --- /dev/null +++ b/.github/actions/docker-login/action.yml @@ -0,0 +1,11 @@ +name: 'Docker Login' +description: 'Login to GitHub Container Registry' +runs: + using: 'composite' + steps: + - name: Login in Github Container registry + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ github.token }} diff --git a/.github/actions/launch-mechanical/action.yml b/.github/actions/launch-mechanical/action.yml new file mode 100644 index 0000000000..b72c27cc6c --- /dev/null +++ b/.github/actions/launch-mechanical/action.yml @@ -0,0 +1,57 @@ +name: 'Launch Mechanical Docker Container' +description: 'Pull and launch Mechanical Docker container' +inputs: + mechanical-image: + description: 'Docker image for Mechanical' + required: true + container-name: + description: 'Name for the Docker container' + required: true + license-server: + description: 'License server address' + required: true + port: + description: 'Port to expose' + required: true + default: '10000' +runs: + using: 'composite' + steps: + - name: Pull and launch Mechanical service + shell: bash + env: + MECHANICAL_IMAGE: ${{ inputs.mechanical-image }} + DOCKER_MECH_CONTAINER_NAME: ${{ inputs.container-name }} + LICENSE_SERVER: ${{ inputs.license-server }} + PYMECHANICAL_PORT: ${{ inputs.port }} + run: | + docker pull ${MECHANICAL_IMAGE} + + echo "Run docker in detached mode" + docker run -d --name ${DOCKER_MECH_CONTAINER_NAME} -e ANSYSLMD_LICENSE_FILE=1055@${LICENSE_SERVER} -p ${PYMECHANICAL_PORT}:10000 ${MECHANICAL_IMAGE} + + # Wait for Mechanical to initialize with intelligent polling + max_wait=300 # Maximum wait time in seconds + check_interval=10 # Check every 10 seconds + elapsed=0 + + echo "Waiting for Mechanical to initialize..." + while [ $elapsed -lt $max_wait ]; do + docker logs ${DOCKER_MECH_CONTAINER_NAME} > log.txt + if grep -q 'WB Initialize Done' log.txt 2>/dev/null; then + echo "Mechanical initialized successfully after ${elapsed} seconds" + break + fi + echo "Waiting for initialization... (${elapsed}/${max_wait}s)" + sleep $check_interval + elapsed=$((elapsed + check_interval)) + done + + # Final check + docker logs ${DOCKER_MECH_CONTAINER_NAME} > log.txt + if ! grep -q 'WB Initialize Done' log.txt 2>/dev/null; then + echo "ERROR: Mechanical failed to initialize within ${max_wait} seconds" + echo "=== Last 50 lines of log.txt ===" + tail -n 50 log.txt || echo "No log file found" + exit 1 + fi diff --git a/.github/actions/setup-python-container/action.yml b/.github/actions/setup-python-container/action.yml new file mode 100644 index 0000000000..cab4a4f669 --- /dev/null +++ b/.github/actions/setup-python-container/action.yml @@ -0,0 +1,42 @@ +name: 'Setup Python Environment in Container' +description: 'Setup Python environment with uv in a container' +inputs: + python-version: + description: 'Python version to install' + required: true + install-testing-deps: + description: 'Whether to install testing dependencies' + required: false + default: 'true' + install-doc-deps: + description: 'Whether to install documentation dependencies' + required: false + default: 'false' +runs: + using: 'composite' + steps: + - name: Set up Python + shell: bash + run: | + apt update + apt install lsb-release xvfb git curl make -y + curl -LsSf https://astral.sh/uv/install.sh | sh + export PATH="$HOME/.local/bin:$PATH" + uv python install python${{ inputs.python-version }} + uv venv /env + + - name: Install packages for testing + if: inputs.install-testing-deps == 'true' + shell: bash + run: | + . /env/bin/activate + uv pip install --upgrade pip + uv pip install -e .[tests] + + - name: Install packages for documentation + if: inputs.install-doc-deps == 'true' + shell: bash + run: | + . /env/bin/activate + uv pip install --upgrade pip + uv pip install -e .[doc] diff --git a/.github/actions/setup-test-env/action.yml b/.github/actions/setup-test-env/action.yml new file mode 100644 index 0000000000..fc90ce4512 --- /dev/null +++ b/.github/actions/setup-test-env/action.yml @@ -0,0 +1,26 @@ +name: 'Setup Test Environment Variables' +description: 'Set common environment variables for testing jobs' +inputs: + container-stable-exit: + description: 'Whether container tests should exit on failure' + required: true + python-version: + description: 'Python version being tested' + required: true + num-cores: + description: 'Number of cores to use' + required: false + default: '1' +runs: + using: 'composite' + steps: + - name: Set common test environment + shell: bash + run: | + echo "ANSYS_WORKBENCH_LOGGING_CONSOLE=0" >> $GITHUB_ENV + echo "ANSYS_WORKBENCH_LOGGING=0" >> $GITHUB_ENV + echo "ANSYS_WORKBENCH_LOGGING_FILTER_LEVEL=2" >> $GITHUB_ENV + echo "CONTAINER_STABLE_EXIT=${{ inputs.container-stable-exit }}" >> $GITHUB_ENV + echo "MATRIX_PYTHON_VERSION=${{ inputs.python-version }}" >> $GITHUB_ENV + echo "NUM_CORES=${{ inputs.num-cores }}" >> $GITHUB_ENV + echo "PYTHONUNBUFFERED=1" >> $GITHUB_ENV diff --git a/.github/actions/upload-coverage/action.yml b/.github/actions/upload-coverage/action.yml new file mode 100644 index 0000000000..f884589363 --- /dev/null +++ b/.github/actions/upload-coverage/action.yml @@ -0,0 +1,32 @@ +name: 'Upload Coverage Results' +description: 'Upload coverage results as artifacts' +inputs: + coverage-name: + description: 'Name suffix for coverage artifacts' + required: true + python-version: + description: 'Python version being tested' + required: true + main-python-version: + description: 'Main Python version to compare against' + required: true +runs: + using: 'composite' + steps: + - name: Upload coverage results (.cov) + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + if: inputs.python-version == inputs.main-python-version + with: + include-hidden-files: true + name: coverage-${{ inputs.coverage-name }} + path: .cov + retention-days: 7 + + - name: Upload coverage results (.coverage) + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + if: inputs.python-version == inputs.main-python-version + with: + include-hidden-files: true + name: coverage-file-${{ inputs.coverage-name }} + path: .coverage + retention-days: 7 diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index f688217ed3..b207cdfcf8 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -199,12 +199,13 @@ jobs: permissions: packages: read # Required to pull Docker images from GitHub Container Registry steps: - - name: Login in Github Container registry - uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + persist-credentials: false + + - name: Login to Docker + uses: ./.github/actions/docker-login - name: Pull, launch, and validate Mechanical service id: get_sha @@ -282,53 +283,23 @@ jobs: packages: read # Required to pull Docker images from GitHub Container Registry checks: write # Needed to publish test results and status checks steps: - - name: Login in Github Container registry - uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + persist-credentials: false + + - name: Login to Docker + uses: ./.github/actions/docker-login - name: Pull, launch, and validate Mechanical service + uses: ./.github/actions/launch-mechanical env: - MECHANICAL_IMAGE: ${{ env.DOCKER_PACKAGE }}:${{ matrix.mechanical-version }} - # ANSYS_WORKBENCH_LOGGING_CONSOLE: 0 - # ANSYS_WORKBENCH_LOGGING_DIRECTORY: /log_file # workbench.log file ANSYS_WORKBENCH_LOGGING_AUTO_FLUSH: 0 # turn off autoflush for faster performance - DOCKER_MECH_CONTAINER_NAME: ${{ env.DOCKER_MECH_CONTAINER_NAME }} - LICENSE_SERVER: ${{ env.LICENSE_SERVER }} - PYMECHANICAL_PORT: ${{ env.PYMECHANICAL_PORT }} - run: | - docker pull ${MECHANICAL_IMAGE} - - echo "Run docker in detached mode" - docker run -d --name ${DOCKER_MECH_CONTAINER_NAME} -e ANSYSLMD_LICENSE_FILE=1055@${LICENSE_SERVER} -p ${PYMECHANICAL_PORT}:10000 ${MECHANICAL_IMAGE} - - # Wait for Mechanical to initialize with intelligent polling - max_wait=300 # Maximum wait time in seconds - check_interval=10 # Check every 10 seconds - elapsed=0 - - echo "Waiting for Mechanical to initialize..." - while [ $elapsed -lt $max_wait ]; do - docker logs ${DOCKER_MECH_CONTAINER_NAME} > log.txt - if grep -q 'WB Initialize Done' log.txt 2>/dev/null; then - echo "Mechanical initialized successfully after ${elapsed} seconds" - break - fi - echo "Waiting for initialization... (${elapsed}/${max_wait}s)" - sleep $check_interval - elapsed=$((elapsed + check_interval)) - done - - # Final check - docker logs ${DOCKER_MECH_CONTAINER_NAME} > log.txt - if ! grep -q 'WB Initialize Done' log.txt 2>/dev/null; then - echo "ERROR: Mechanical failed to initialize within ${max_wait} seconds" - echo "=== Last 50 lines of log.txt ===" - tail -n 50 log.txt || echo "No log file found" - exit 1 - fi + with: + mechanical-image: ${{ env.DOCKER_PACKAGE }}:${{ matrix.mechanical-version }} + container-name: ${{ env.DOCKER_MECH_CONTAINER_NAME }} + license-server: ${{ env.LICENSE_SERVER }} + port: ${{ env.PYMECHANICAL_PORT }} - name: Display info if: github.event_name == 'schedule' @@ -367,22 +338,12 @@ jobs: fail_on_failure: true - name: Upload coverage results - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - if: matrix.mechanical-version == needs.revn-variations.outputs.test_docker_image_version - with: - include-hidden-files: true - name: coverage-tests - path: .cov - retention-days: 7 - - - name: Upload coverage results (as .coverage) - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: ./.github/actions/upload-coverage if: matrix.mechanical-version == needs.revn-variations.outputs.test_docker_image_version with: - include-hidden-files: true - name: coverage-file-tests - path: .coverage - retention-days: 7 + coverage-name: tests + python-version: ${{ env.MAIN_PYTHON_VERSION }} + main-python-version: ${{ env.MAIN_PYTHON_VERSION }} - name: Get Mechanical container logs if: always() @@ -422,21 +383,10 @@ jobs: persist-credentials: false - name: Set up Python - shell: bash - env: - MAIN_PYTHON_VERSION: ${{ env.MAIN_PYTHON_VERSION }} - run: | - apt update - apt install lsb-release xvfb git curl make -y - curl -LsSf https://astral.sh/uv/install.sh | sh - export PATH="$HOME/.local/bin:$PATH" - uv python install python${MAIN_PYTHON_VERSION} - uv venv /env - - name: "Install packages for testing" - run: | - . /env/bin/activate - uv pip install --upgrade pip - uv pip install -e .[tests] + uses: ./.github/actions/setup-python-container + with: + python-version: ${{ env.MAIN_PYTHON_VERSION }} + install-testing-deps: 'true' - name: Unit Testing and coverage env: @@ -456,22 +406,11 @@ jobs: fi - name: Upload coverage results - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - if: env.MAIN_PYTHON_VERSION == matrix.python-version + uses: ./.github/actions/upload-coverage with: - include-hidden-files: true - name: coverage-tests-embedding - path: .cov - retention-days: 7 - - - name: Upload coverage results (as .coverage) - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - if: env.MAIN_PYTHON_VERSION == matrix.python-version - with: - include-hidden-files: true - name: coverage-file-tests-embedding - path: .coverage - retention-days: 7 + coverage-name: tests-embedding + python-version: ${{ matrix.python-version }} + main-python-version: ${{ env.MAIN_PYTHON_VERSION }} - name: Publish Test Report uses: mikepenz/action-junit-report@a294a61c909bd8a4b563024a2faa28897fd53ebc # v6.1.0 @@ -505,21 +444,10 @@ jobs: persist-credentials: false - name: Set up Python - shell: bash - env: - MAIN_PYTHON_VERSION: ${{ env.MAIN_PYTHON_VERSION }} - run: | - apt update - apt install lsb-release xvfb git curl make -y - curl -LsSf https://astral.sh/uv/install.sh | sh - export PATH="$HOME/.local/bin:$PATH" - uv python install python${MAIN_PYTHON_VERSION} - uv venv /env - - name: "Install packages for testing" - run: | - . /env/bin/activate - uv pip install --upgrade pip - uv pip install -e .[tests] + uses: ./.github/actions/setup-python-container + with: + python-version: ${{ env.MAIN_PYTHON_VERSION }} + install-testing-deps: 'true' - name: Embedding scripts unit testing and coverage env: @@ -535,22 +463,11 @@ jobs: pytest -m cli -s --junitxml test_results_cli_scripts${MAIN_PYTHON_VERSION}.xml - name: Upload coverage results - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - if: env.MAIN_PYTHON_VERSION == matrix.python-version - with: - include-hidden-files: true - name: coverage-tests-embedding-scripts - path: .cov - retention-days: 7 - - - name: Upload coverage results (as .coverage) - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - if: env.MAIN_PYTHON_VERSION == matrix.python-version + uses: ./.github/actions/upload-coverage with: - include-hidden-files: true - name: coverage-file-tests-embedding-scripts - path: .coverage - retention-days: 7 + coverage-name: tests-embedding-scripts + python-version: ${{ matrix.python-version }} + main-python-version: ${{ env.MAIN_PYTHON_VERSION }} - name: Publish Test Report uses: mikepenz/action-junit-report@a294a61c909bd8a4b563024a2faa28897fd53ebc # v6.1.0 @@ -584,21 +501,10 @@ jobs: persist-credentials: false - name: Set up Python - shell: bash - env: - MAIN_PYTHON_VERSION: ${{ env.MAIN_PYTHON_VERSION }} - run: | - apt update - apt install lsb-release xvfb git curl make -y - curl -LsSf https://astral.sh/uv/install.sh | sh - export PATH="$HOME/.local/bin:$PATH" - uv python install python${MAIN_PYTHON_VERSION} - uv venv /env - - name: "Install packages for testing" - run: | - . /env/bin/activate - uv pip install --upgrade pip - uv pip install -e .[tests] + uses: ./.github/actions/setup-python-container + with: + python-version: ${{ env.MAIN_PYTHON_VERSION }} + install-testing-deps: 'true' - name: Set environment variable env: @@ -631,22 +537,11 @@ jobs: fail_on_failure: true - name: Upload coverage results - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - if: env.MAIN_PYTHON_VERSION == matrix.python-version - with: - include-hidden-files: true - name: coverage-tests-remote-session-launch - path: .cov - retention-days: 7 - - - name: Upload coverage results (as .coverage) - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - if: env.MAIN_PYTHON_VERSION == matrix.python-version + uses: ./.github/actions/upload-coverage with: - include-hidden-files: true - name: coverage-file-tests-remote-session-launch - path: .coverage - retention-days: 7 + coverage-name: tests-remote-session-launch + python-version: ${{ matrix.python-version }} + main-python-version: ${{ env.MAIN_PYTHON_VERSION }} doc-build: name: Documentation @@ -667,16 +562,11 @@ jobs: persist-credentials: false - name: Set up Python - shell: bash - env: - MAIN_PYTHON_VERSION: ${{ env.MAIN_PYTHON_VERSION }} - run: | - apt update - apt install lsb-release xvfb git curl make -y - curl -LsSf https://astral.sh/uv/install.sh | sh - export PATH="$HOME/.local/bin:$PATH" - uv python install python${MAIN_PYTHON_VERSION} - uv venv /env + uses: ./.github/actions/setup-python-container + with: + python-version: ${{ env.MAIN_PYTHON_VERSION }} + install-testing-deps: 'false' + install-doc-deps: 'true' - name: Install system dependencies env: @@ -698,6 +588,8 @@ jobs: && apt install gh -y - name: Install quarto to build cheatsheet + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | # zizmor: ignore[template-injection] echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token gh release download v1.6.43 --repo github.com/quarto-dev/quarto-cli --pattern *linux-amd64.deb @@ -707,12 +599,6 @@ jobs: - name: Test quarto installation run: quarto --version - - name: Install Python requirements - run: | - . /env/bin/activate - uv pip install --upgrade pip - uv pip install -e .[doc] - - name: Build docs env: NUM_CORES: 1 diff --git a/doc/changelog.d/1465.miscellaneous.md b/doc/changelog.d/1465.miscellaneous.md new file mode 100644 index 0000000000..69a482686e --- /dev/null +++ b/doc/changelog.d/1465.miscellaneous.md @@ -0,0 +1 @@ +Ci/cd