diff --git a/.github/docker/debian/bookworm/amd64/CI/Dockerfile b/.github/docker/debian/bookworm/amd64/CI/Dockerfile new file mode 100644 index 00000000000..0fd3cec5f4c --- /dev/null +++ b/.github/docker/debian/bookworm/amd64/CI/Dockerfile @@ -0,0 +1,24 @@ +ARG BUILDER_IMAGE=signalwire/freeswitch-public-ci-base:bookworm-amd64 + +FROM ${BUILDER_IMAGE} + +ARG MAINTAINER_EMAIL="andrey@signalwire.com" + +LABEL org.opencontainers.image.authors="${MAINTAINER_EMAIL}" + +SHELL ["/bin/bash", "-c"] + +COPY --from=sofia-sip / /usr/src/sofia-sip +COPY --from=freeswitch / /usr/src/freeswitch + +RUN cd /usr/src/freeswitch && \ + ./ci.sh -t unit-test -a configure -c sofia-sip -p "/usr/src/sofia-sip" && \ + ./ci.sh -t unit-test -a build -c sofia-sip -p "/usr/src/sofia-sip" && \ + ./ci.sh -t unit-test -a install -c sofia-sip -p "/usr/src/sofia-sip" && \ + ./ci.sh -t unit-test -a configure -c freeswitch -p "/usr/src/freeswitch" && \ + ./ci.sh -t unit-test -a build -c freeswitch -p "/usr/src/freeswitch" && \ + ./ci.sh -t unit-test -a install -c freeswitch -p "/usr/src/freeswitch" + +WORKDIR /usr/src/freeswitch/tests/unit + +ENTRYPOINT ["/usr/src/freeswitch/tests/unit/run-tests.sh"] diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 49e99e8b48b..ea0d0a28fe6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,12 +9,32 @@ on: paths: - "**" workflow_dispatch: + inputs: + freeswitch_ref: + description: 'FreeSWITCH repository ref' + required: true + default: master + type: string + release: + description: 'FreeSWITCH release type' + type: choice + required: true + default: unstable + options: + - release + - unstable + publish: + description: 'Publish build data' + required: true + default: false + type: boolean concurrency: group: ${{ github.head_ref || github.ref }} jobs: preconfig: + name: 'Preconfig' runs-on: ubuntu-latest outputs: deb: ${{ steps.deb.outputs.excludes }} @@ -59,6 +79,8 @@ jobs: elif [[ '${{ github.base_ref }}' == 'v1.10' ]]; then echo 'release=release' | tee -a $GITHUB_OUTPUT fi + elif [[ '${{ github.event_name }}' == 'workflow_dispatch' ]]; then + echo 'release=${{ inputs.release }}' | tee -a $GITHUB_OUTPUT elif [[ '${{ github.ref }}' == 'refs/heads/master' ]]; then echo 'release=unstable' | tee -a $GITHUB_OUTPUT elif [[ '${{ github.ref }}' == 'refs/heads/v1.10' ]]; then @@ -67,6 +89,33 @@ jobs: exit 1 fi + get-nonce: + name: 'Get Nonce for token' + runs-on: freeswitch-repo-auth-client + outputs: + nonce: ${{ steps.get-nonce.outputs.nonce }} + steps: + - name: Get Nonce + id: get-nonce + uses: signalwire/actions-template/.github/actions/repo-auth-client@main + with: + mode: nonce + + issue-token: + name: 'Issue temporary token' + runs-on: ubuntu-latest + needs: get-nonce + outputs: + token: ${{ steps.issue-token.outputs.token }} + steps: + - name: Issue Token + id: issue-token + uses: signalwire/actions-template/.github/actions/repo-auth-client@main + env: + NONCE: ${{ needs.get-nonce.outputs.nonce }} + with: + mode: issue + deb-public: name: 'DEB-PUBLIC' permissions: @@ -74,6 +123,7 @@ jobs: contents: read needs: - preconfig + - issue-token uses: signalwire/actions-template/.github/workflows/cicd-docker-build-and-distribute.yml@main strategy: # max-parallel: 1 @@ -96,6 +146,7 @@ jobs: exclude: ${{ fromJson(needs.preconfig.outputs.deb) }} with: RUNNER: ${{ matrix.platform.runner }} + REF: ${{ inputs.freeswitch_ref }} ARTIFACTS_PATTERN: '.*\.(deb|dsc|changes|tar.bz2|tar.gz|tar.lzma|tar.xz)$' DOCKERFILE: .github/docker/${{ matrix.os }}/${{ matrix.version }}/${{ matrix.platform.name }}/public.${{ matrix.release }}.Dockerfile MAINTAINER: 'Andrey Volk ' @@ -103,7 +154,17 @@ jobs: PLATFORM: ${{ matrix.platform.name }} REPO_DOMAIN: 'freeswitch.signalwire.com' TARGET_ARTIFACT_NAME: ${{ matrix.os }}-${{ matrix.version }}-${{ matrix.platform.name }}-public-${{ matrix.release }}-artifact - UPLOAD_BUILD_ARTIFACTS: ${{ github.event_name != 'pull_request' || contains(github.event.pull_request.title, ':upload-artifacts') }} + UPLOAD_BUILD_ARTIFACTS: >- + ${{ + (github.event.pull_request.head.repo.full_name == github.repository) && + ( + ( + github.event_name != 'pull_request' && + github.event_name != 'workflow_dispatch' + ) || + (github.event_name == 'workflow_dispatch' && inputs.publish) + ) + }} secrets: GH_BOT_DEPLOY_TOKEN: ${{ secrets.PAT }} HOSTNAME: ${{ secrets.HOSTNAME }} @@ -111,11 +172,37 @@ jobs: USERNAME: ${{ secrets.USERNAME }} TELEPORT_TOKEN: ${{ secrets.TELEPORT_TOKEN }} REPO_USERNAME: 'SWUSERNAME' - REPO_PASSWORD: ${{ secrets.REPOTOKEN }} + REPO_PASSWORD: ${{ needs.issue-token.outputs.token }} + + revoke-token: + name: 'Revoke temporary token' + runs-on: ubuntu-latest + # if: always() + needs: + - issue-token + - deb-public + steps: + - name: Revoke Token + id: revoke-token + uses: signalwire/actions-template/.github/actions/repo-auth-client@main + env: + TOKEN: ${{ needs.issue-token.outputs.token }} + with: + mode: revoke meta: name: 'Publish build data to meta-repo' - if: ${{ github.event_name != 'pull_request' || contains(github.event.pull_request.title, ':upload-artifacts') }} + if: >- + ${{ + (github.event.pull_request.head.repo.full_name == github.repository) && + ( + ( + github.event_name != 'pull_request' && + github.event_name != 'workflow_dispatch' + ) || + (github.event_name == 'workflow_dispatch' && inputs.publish) + ) + }} needs: - deb-public permissions: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51586fabfe7..0a774108e0a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,18 +4,45 @@ on: push: branches: - master + - v1.10 pull_request: types: - opened - synchronize + workflow_dispatch: + inputs: + freeswitch_ref: + description: 'FreeSWITCH repository ref' + required: false + type: string + sofia-sip_ref: + description: 'Sofia-Sip repository ref' + required: false + type: string + dind: + description: 'Run tests using Docker-in-Docker' + required: false + type: boolean + default: false + +env: + CI_BASE_STATIC_IMAGE: signalwire/freeswitch-public-ci-base:bookworm-amd64 + DOCKER_BUILD_SUMMARY: false + DOCKER_BUILD_CHECKS_ANNOTATIONS: false + DOCKER_BUILD_RECORD_UPLOAD: false jobs: unit-tests-pre-config: + if: ${{ !inputs.dind }} + name: "Unit-tests pre-config" runs-on: ubuntu-latest env: TOTAL_GROUPS: 2 outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} + container-image: ${{ steps.set-vars.outputs.container-image }} + working-directory: ${{ steps.set-vars.outputs.working-directory }} + tests-only: ${{ steps.set-vars.outputs.tests-only }} steps: - id: set-matrix shell: bash @@ -25,81 +52,52 @@ jobs: include: [range(1; $groups + 1) | {group: ., total: $groups}] }') echo "matrix=$MATRIX" | tee -a $GITHUB_OUTPUT + - id: set-vars + shell: bash + run: | + echo "tests-only=false" >> $GITHUB_OUTPUT + echo "working-directory=freeswitch/tests/unit" >> $GITHUB_OUTPUT + echo "container-image=$CI_BASE_STATIC_IMAGE" >> $GITHUB_OUTPUT unit-tests: - needs: unit-tests-pre-config + if: ${{ !inputs.dind }} + name: "Unit-tests (group ${{ matrix.group }})" + needs: + - unit-tests-pre-config strategy: + fail-fast: false matrix: ${{ fromJson(needs.unit-tests-pre-config.outputs.matrix) }} - name: "unit-tests (group ${{ matrix.group }})" uses: ./.github/workflows/unit-test.yml with: total-groups: ${{ matrix.total }} current-group: ${{ matrix.group }} + container-image: ${{ needs.unit-tests-pre-config.outputs.container-image }} + working-directory: ${{ needs.unit-tests-pre-config.outputs.working-directory }} + tests-only: ${{ fromJson(needs.unit-tests-pre-config.outputs.tests-only) }} secrets: inherit - scan-build: + validate-unit-tests: + if: ${{ always() && !inputs.dind }} + name: "Validate Unit-tests" + needs: unit-tests runs-on: ubuntu-latest - container: - image: signalwire/freeswitch-public-base:bookworm - credentials: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - options: --privileged - env: - REPOTOKEN: ${{ secrets.REPOTOKEN }} - DEBIAN_FRONTEND: noninteractive - steps: - - name: Install dependencies - shell: bash + - name: Check unit tests status run: | - echo "machine freeswitch.signalwire.com password $REPOTOKEN" > /etc/apt/auth.conf && \ - apt-get update && \ - apt-get -y remove \ - libsofia-sip-ua0 \ - libspandsp-dev && \ - apt-get -y install \ - autoconf \ - libsofia-sip-ua-dev \ - libspandsp3-dev && \ - rm -rf /etc/apt/auth.conf - - - name: Checkout code - uses: actions/checkout@v4 - with: - path: /__w/freeswitch/freeswitch + if [ "${{ needs.unit-tests.result }}" != "success" ]; then + exit 1 + fi - - name: Bootstrap - shell: bash - working-directory: /__w/freeswitch/freeswitch - run: | - ./bootstrap.sh -j || exit 1 + unit-tests-dind: + if: ${{ inputs.dind }} + name: "Unit-tests D-in-D" + uses: ./.github/workflows/unit-test-dind.yml + with: + freeswitch_ref: ${{ inputs.freeswitch_ref }} + sofia-sip_ref: ${{ inputs.sofia-sip_ref }} + secrets: inherit - - name: Scan-build FreeSwitch - shell: bash - working-directory: /__w/freeswitch/freeswitch - run: | - cp build/modules.conf.most modules.conf && \ - echo 'codecs/mod_openh264' >> modules.conf && \ - sed -i \ - -e '/mod_mariadb/s/^#//g' \ - -e '/mod_v8/s/^#//g' \ - -e '/mod_ilbc/s/^/#/g' \ - -e '/mod_isac/s/^/#/g' \ - -e '/mod_mp4/s/^/#/g' \ - -e '/mod_mongo/s/^/#/g' \ - -e '/mod_pocketsphinx/s/^/#/g' \ - -e '/mod_sangoma_codec/s/^/#/g' \ - -e '/mod_siren/s/^/#/g' \ - -e '/mod_avmd/s/^/#/g' \ - -e '/mod_basic/s/^/#/g' \ - -e '/mod_cdr_mongodb/s/^/#/g' \ - -e '/mod_cv/s/^/#/g' \ - -e '/mod_erlang_event/s/^/#/g' \ - -e '/mod_perl/s/^/#/g' \ - -e '/mod_rtmp/s/^/#/g' \ - -e '/mod_unimrcp/s/^/#/g' \ - -e '/mod_xml_rpc/s/^/#/g' \ - modules.conf && \ - ./configure && \ - ./scan_build.sh + scan-build: + name: "Scan Build" + uses: ./.github/workflows/scan-build.yml + secrets: inherit diff --git a/.github/workflows/scan-build.yml b/.github/workflows/scan-build.yml new file mode 100644 index 00000000000..b274f45d6bf --- /dev/null +++ b/.github/workflows/scan-build.yml @@ -0,0 +1,99 @@ +name: Scan build (Static Analysis) + +on: + workflow_call: + inputs: + freeswitch_ref: + description: 'FreeSWITCH repository ref' + required: false + type: string + sofia-sip_ref: + description: 'Sofia-Sip repository ref' + required: false + type: string + +jobs: + scan-build: + runs-on: ubuntu-latest + container: + image: signalwire/freeswitch-public-ci-base:bookworm-amd64 + options: --privileged + env: + DEBIAN_FRONTEND: noninteractive + + steps: + - name: Checkout Sofia-Sip + if: inputs.sofia-sip_ref == '' + uses: actions/checkout@v4 + with: + repository: freeswitch/sofia-sip + path: sofia-sip + + - name: Checkout Sofia-Sip (via ref) + if: inputs.sofia-sip_ref != '' + uses: actions/checkout@v4 + with: + repository: freeswitch/sofia-sip + ref: ${{ inputs.sofia-sip_ref }} + path: sofia-sip + + - name: Checkout FreeSWITCH (via ref) + if: inputs.freeswitch_ref != '' + uses: actions/checkout@v4 + with: + ref: ${{ inputs.freeswitch_ref }} + path: freeswitch + + - name: Checkout FreeSWITCH + if: inputs.freeswitch_ref == '' + uses: actions/checkout@v4 + with: + path: freeswitch + + - name: Configure, Build and Install Sofia-Sip + shell: bash + working-directory: freeswitch + run: | + ./ci.sh -t scan-build -a configure -c sofia-sip -p "$GITHUB_WORKSPACE/sofia-sip" + ./ci.sh -t scan-build -a build -c sofia-sip -p "$GITHUB_WORKSPACE/sofia-sip" + ./ci.sh -t scan-build -a install -c sofia-sip -p "$GITHUB_WORKSPACE/sofia-sip" + + - name: Configure FreeSWITCH + shell: bash + working-directory: freeswitch + run: | + ./ci.sh -t scan-build -a configure -c freeswitch -p "$GITHUB_WORKSPACE/freeswitch" + + - name: Run scan-build analysis + shell: bash + working-directory: freeswitch + run: | + ./ci.sh -t scan-build -a build -c freeswitch -p "$GITHUB_WORKSPACE/freeswitch" + + - name: Check analysis results + if: always() + shell: bash + working-directory: freeswitch + run: | + ./ci.sh -t scan-build -a validate -c freeswitch -p "$GITHUB_WORKSPACE/freeswitch" + + - name: Upload Scan-Build logs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: scan-build-logs + path: freeswitch/scan-build + if-no-files-found: ignore + compression-level: 9 + + - name: Notify run tests result to slack + if: | + failure() && + github.event_name == 'push' && + (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/v1.10') + uses: signalwire/actions-template/.github/actions/slack@main + with: + CHANNEL: ${{ secrets.SLACK_DEVOPS_CI_CHANNEL }} + MESSAGE: Scan-Build ${{ github.repository }} > <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ github.run_id }}>. Static analysis failed. + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/unit-test-dind.yml b/.github/workflows/unit-test-dind.yml new file mode 100644 index 00000000000..ca3abd5a6f6 --- /dev/null +++ b/.github/workflows/unit-test-dind.yml @@ -0,0 +1,100 @@ +name: Unit-tests D-in-D + +on: + workflow_call: + inputs: + freeswitch_ref: + description: 'FreeSWITCH repository ref' + required: false + type: string + sofia-sip_ref: + description: 'Sofia-Sip repository ref' + required: false + type: string + +env: + MAX_CONTAINERS: 8 + NUM_CPU_PER_CONTAINER: 1 + DOCKER_BUILD_SUMMARY: false + DOCKER_BUILD_CHECKS_ANNOTATIONS: false + DOCKER_BUILD_RECORD_UPLOAD: false + +jobs: + unit-tests: + runs-on: ubuntu-latest + container: + image: signalwire/freeswitch-public-ci-base:bookworm-amd64 + options: --privileged + env: + DEBIAN_FRONTEND: noninteractive + ASAN_OPTIONS: log_path=stdout:disable_coredump=0:unmap_shadow_on_exit=1:fast_unwind_on_malloc=0 + + steps: + - name: Checkout Sofia-Sip (via ref) + if: inputs.sofia-sip_ref != '' + uses: actions/checkout@v4 + with: + repository: freeswitch/sofia-sip + ref: ${{ inputs.sofia-sip_ref }} + path: sofia-sip + + - name: Checkout Sofia-Sip + if: inputs.sofia-sip_ref == '' + uses: actions/checkout@v4 + with: + repository: freeswitch/sofia-sip + path: sofia-sip + + - name: Checkout FreeSWITCH (via ref) + if: inputs.freeswitch_ref != '' + uses: actions/checkout@v4 + with: + ref: ${{ inputs.freeswitch_ref }} + path: freeswitch + + - name: Checkout FreeSWITCH + if: inputs.freeswitch_ref == '' + uses: actions/checkout@v4 + with: + path: freeswitch + + - name: Run Unit-Test containers and collect artifacts + id: unit_tests + shell: bash + run: | + echo "logs_path=${GITHUB_WORKSPACE}/freeswitch/tests/unit/logs" >> $GITHUB_OUTPUT + + "${GITHUB_WORKSPACE}/freeswitch/tests/unit/run-tests-docker.sh" \ + --base-image signalwire/freeswitch-public-ci-base:bookworm-amd64 \ + --cpus ${{ env.NUM_CPU_PER_CONTAINER }} \ + --image-tag ci.local \ + --max-containers ${{ env.MAX_CONTAINERS }} \ + --output-dir "${GITHUB_WORKSPACE}/freeswitch/tests/unit/logs" \ + --sofia-sip-path "${GITHUB_WORKSPACE}/sofia-sip" \ + --freeswitch-path "${GITHUB_WORKSPACE}/freeswitch" + + test -d "/cores" && ls -lah /cores + + cd "${GITHUB_WORKSPACE}/freeswitch/tests/unit/" && \ + ./collect-test-logs.sh --dir logs --print + + - name: Upload Unit-Test logs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: test-results-${{ github.sha }}-${{ github.run_number }} + path: ${{ steps.unit_tests.outputs.logs_path }} + if-no-files-found: ignore + compression-level: 9 + + - name: Notify run tests result to slack + if: | + failure() && + github.event_name == 'push' && + (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/v1.10') + uses: signalwire/actions-template/.github/actions/slack@main + with: + CHANNEL: ${{ secrets.SLACK_DEVOPS_CI_CHANNEL }} + MESSAGE: Unit-Tests ${{ github.repository }} > <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ github.run_id }}>. Some tests are failing. + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 5db97620a4f..fc108b0ffe4 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -7,19 +7,41 @@ on: description: 'Total number of test groups' required: true type: number + default: 1 current-group: description: 'Current test group number' required: true type: number + default: 1 + freeswitch_ref: + description: 'FreeSWITCH repository ref' + required: false + type: string + sofia-sip_ref: + description: 'Sofia-Sip repository ref' + required: false + type: string + container-image: + description: 'Container image to use for running tests' + required: false + type: string + default: 'signalwire/freeswitch-public-ci-base:bookworm-amd64' + working-directory: + description: 'Working directory for running tests' + required: false + type: string + default: 'freeswitch/tests/unit' + tests-only: + description: 'Run only tests, skip other tasks' + required: false + type: boolean + default: false jobs: unit-test: runs-on: ubuntu-latest container: - image: signalwire/freeswitch-public-base:bookworm - credentials: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} + image: ${{ inputs.container-image }} options: --privileged env: DEBIAN_FRONTEND: noninteractive @@ -29,83 +51,86 @@ jobs: - name: Override core_pattern shell: bash run: | - cat /proc/sys/kernel/core_pattern echo '/cores/core.%s.%E.%e.%p.%t' > /proc/sys/kernel/core_pattern cat /proc/sys/kernel/core_pattern - - name: Install dependencies - shell: bash - env: - REPOTOKEN: ${{ secrets.REPOTOKEN }} - run: | - echo "machine freeswitch.signalwire.com password $REPOTOKEN" > /etc/apt/auth.conf && \ - apt-get update && \ - apt-get -y remove \ - libsofia-sip-ua0 \ - libspandsp-dev && \ - apt-get -y install \ - libspandsp3-dev && \ - rm -rf /etc/apt/auth.conf - - - name: Checkout code + - name: Checkout Sofia-Sip (via ref) + if: ${{ !inputs.tests-only && inputs.sofia-sip_ref != '' }} uses: actions/checkout@v4 with: - path: /__w/freeswitch/freeswitch - - - name: Bootstrap - shell: bash - working-directory: /__w/freeswitch/freeswitch - run: | - ./bootstrap.sh -j || exit 1 + repository: freeswitch/sofia-sip + ref: ${{ inputs.sofia-sip_ref }} + path: sofia-sip - name: Checkout Sofia-Sip + if: ${{ !inputs.tests-only && inputs.sofia-sip_ref == '' }} uses: actions/checkout@v4 with: repository: freeswitch/sofia-sip - path: /__w/freeswitch/freeswitch/sofia-sip + path: sofia-sip + + - name: Checkout FreeSWITCH (via ref) + if: ${{ !inputs.tests-only && inputs.freeswitch_ref != '' }} + uses: actions/checkout@v4 + with: + ref: ${{ inputs.freeswitch_ref }} + path: freeswitch + + - name: Checkout FreeSWITCH + if: ${{ !inputs.tests-only && inputs.freeswitch_ref == '' }} + uses: actions/checkout@v4 + with: + path: freeswitch - - name: Build sofia-sip + - name: Configure, Build and Install Sofia-Sip + if: ${{ !inputs.tests-only }} shell: bash - working-directory: /__w/freeswitch/freeswitch/sofia-sip + working-directory: freeswitch run: | - ./autogen.sh && \ - ./configure.gnu && \ - make -j$(nproc --all) install + ./ci.sh -t unit-test -a configure -c sofia-sip -p "$GITHUB_WORKSPACE/sofia-sip" + ./ci.sh -t unit-test -a build -c sofia-sip -p "$GITHUB_WORKSPACE/sofia-sip" + ./ci.sh -t unit-test -a install -c sofia-sip -p "$GITHUB_WORKSPACE/sofia-sip" - - name: Build FreeSwitch + - name: Configure, Build and Install FreeSWITCH + if: ${{ !inputs.tests-only }} shell: bash - working-directory: /__w/freeswitch/freeswitch + working-directory: freeswitch run: | - echo 'codecs/mod_openh264' >> modules.conf && \ - sed -i \ - -e '/applications\/mod_http_cache/s/^#//g' \ - -e '/event_handlers\/mod_rayo/s/^#//g' \ - -e '/formats\/mod_opusfile/s/^#//g' \ - -e '/languages\/mod_lua/s/^#//g' \ - modules.conf && \ - ./configure \ - --enable-address-sanitizer \ - --enable-fake-dlclose && \ - make -j$(nproc --all) |& tee ./unit-tests-build-result.txt + ./ci.sh -t unit-test -a configure -c freeswitch -p "$GITHUB_WORKSPACE/freeswitch" + ./ci.sh -t unit-test -a build -c freeswitch -p "$GITHUB_WORKSPACE/freeswitch" + ./ci.sh -t unit-test -a install -c freeswitch -p "$GITHUB_WORKSPACE/freeswitch" - echo ${PIPESTATUS[0]} > ./build-status.txt - if ! test "$(cat ./build-status.txt | tr -d '[:space:]')" -eq 0; then - exit "$(cat ./build-status.txt | tr -d '[:space:]')" - fi - make install + - name: Run unit tests + shell: bash + working-directory: ${{ inputs.working-directory }} + run: | + ./run-tests.sh ${{ inputs.total-groups }} ${{ inputs.current-group }} --output-dir logs || exit 1 - - name: Run tests + - name: Collect unit test logs + if: always() shell: bash - working-directory: /__w/freeswitch/freeswitch/tests/unit + working-directory: ${{ inputs.working-directory }} run: | - ./run-tests.sh ${{ inputs.total-groups }} ${{ inputs.current-group }} - mkdir logs && (mv log_run-tests_*.html logs || true) && (mv backtrace_*.txt logs || true) - ./collect-test-logs.sh + test -d "/cores" && ls -lah /cores + ./collect-test-logs.sh --dir logs --print - - name: Notify result + - name: Upload Unit-Test logs if: failure() - uses: signalwire/actions-template/.github/actions/notify-ci-result@main + uses: actions/upload-artifact@v4 with: - for: "run_tests" - test_logs_path: /__w/freeswitch/freeswitch/tests/unit - test_artifacts_suffix: "-${{ inputs.current-group }}" + name: test-results-${{ github.sha }}-${{ github.run_number }}-${{ inputs.current-group }}-of-${{ inputs.total-groups }} + path: ${{ inputs.working-directory }}/logs + if-no-files-found: ignore + compression-level: 9 + + - name: Notify run tests result to slack + if: | + failure() && + github.event_name == 'push' && + (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/v1.10') + uses: signalwire/actions-template/.github/actions/slack@main + with: + CHANNEL: ${{ secrets.SLACK_DEVOPS_CI_CHANNEL }} + MESSAGE: Unit-Tests ${{ github.repository }} > <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ github.run_id }}>. Some tests are failing. + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml new file mode 100644 index 00000000000..5d59fba2a1d --- /dev/null +++ b/.github/workflows/windows.yml @@ -0,0 +1,28 @@ +name: Windows + +on: + pull_request: + types: [opened, synchronize] + push: + branches: [master, release] +jobs: + x64: + runs-on: windows-2019 + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v2 + + - name: Build + run: msbuild Freeswitch.2017.sln -t:build -verbosity:minimal -property:Configuration=Release -property:Platform=x64 + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: MSI Package + path: D:\a\freeswitch\freeswitch\x64\*.msi + if: contains(github.event.pull_request.title, ':upload-artifacts') || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/v1.10' diff --git a/build/modmake.rulesam b/build/modmake.rulesam index 5ccdf8b5c20..9e4eb56f975 100644 --- a/build/modmake.rulesam +++ b/build/modmake.rulesam @@ -17,5 +17,4 @@ extraclean-modules: extraclean print_tests: @set +e; \ - test -z "$(TESTS)" || for i in $(TESTS); do echo $(subdir)/$$i; done; - \ No newline at end of file + test -z "$(TESTS)" || for i in $(TESTS); do echo $(subdir)/$$i; done; echo; diff --git a/ci.sh b/ci.sh new file mode 100755 index 00000000000..c8d9e848cce --- /dev/null +++ b/ci.sh @@ -0,0 +1,259 @@ +#!/usr/bin/env bash + +### shfmt -w -s -ci -sr -kp -fn ci.sh + +#------------------------------------------------------------------------------ +# CI Script +# Helper script for running CI jobs +#------------------------------------------------------------------------------ + +# Function to display usage information +display_usage() +{ + echo "Usage: $0 -t -a -c -p " + echo "Options:" + echo " -t Type (unit-test, scan-build)" + echo " -a Action (configure, build, install, validate)" + echo " -c Code (sofia-sip, freeswitch)" + echo " -p Path to code" + exit 1 +} + +# Parse command line arguments +while getopts "t:p:a:c:h" opt; do + case $opt in + t) TYPE="$OPTARG" ;; + a) ACTION="$OPTARG" ;; + c) CODE="$OPTARG" ;; + p) PATH_TO_CODE="$OPTARG" ;; + h) display_usage ;; + ?) display_usage ;; + esac +done + +# Function to handle sofia-sip configuration +configure_sofia_sip() +{ + ./autogen.sh && ./configure.gnu || exit 1 +} + +# Function to handle sofia-sip build +build_sofia_sip() +{ + make -j$(nproc) || exit 1 +} + +# Function to handle sofia-sip installation +install_sofia_sip() +{ + make install || exit 1 +} + +# Function to handle sofia-sip validation +validate_sofia_sip() +{ + exit 0 +} + +# Function to handle freeswitch configuration +configure_freeswitch() +{ + local type="$1" + + ./bootstrap.sh -j || exit 1 + + case "$type" in + "unit-test") + echo 'codecs/mod_openh264' >> modules.conf + sed -i \ + -e '/applications\/mod_http_cache/s/^#//g' \ + -e '/event_handlers\/mod_rayo/s/^#//g' \ + -e '/formats\/mod_opusfile/s/^#//g' \ + -e '/languages\/mod_lua/s/^#//g' \ + modules.conf + + export ASAN_OPTIONS=log_path=stdout:disable_coredump=0:unmap_shadow_on_exit=1:fast_unwind_on_malloc=0 + + ./configure \ + --enable-address-sanitizer \ + --enable-fake-dlclose || + exit 1 + + ;; + "scan-build") + cp build/modules.conf.most modules.conf + + # "Enable"/"Uncomment" mods + echo 'codecs/mod_openh264' >> modules.conf + sed -i \ + -e '/mod_mariadb/s/^#//g' \ + -e '/mod_v8/s/^#//g' \ + modules.conf + + # "Disable"/"Comment out" mods + sed -i \ + -e '/mod_ilbc/s/^/#/g' \ + -e '/mod_isac/s/^/#/g' \ + -e '/mod_mp4/s/^/#/g' \ + -e '/mod_mongo/s/^/#/g' \ + -e '/mod_pocketsphinx/s/^/#/g' \ + -e '/mod_sangoma_codec/s/^/#/g' \ + -e '/mod_siren/s/^/#/g' \ + -e '/mod_avmd/s/^/#/g' \ + -e '/mod_basic/s/^/#/g' \ + -e '/mod_cdr_mongodb/s/^/#/g' \ + -e '/mod_cv/s/^/#/g' \ + -e '/mod_erlang_event/s/^/#/g' \ + -e '/mod_perl/s/^/#/g' \ + -e '/mod_rtmp/s/^/#/g' \ + -e '/mod_unimrcp/s/^/#/g' \ + -e '/mod_xml_rpc/s/^/#/g' \ + modules.conf + + ./configure || exit 1 + + ;; + *) + exit 1 + ;; + esac +} + +# Function to handle freeswitch build +build_freeswitch() +{ + local type="$1" + + set -o pipefail + + case "$type" in + "unit-test") + make --no-keep-going -j$(nproc --all) |& tee ./unit-tests-build-result.txt + build_status=${PIPESTATUS[0]} + if [[ $build_status != "0" ]]; then + exit $build_status + fi + + ;; + "scan-build") + if ! command -v scan-build-14 > /dev/null 2>&1; then + echo "Error: scan-build-14 command not found. Please ensure clang static analyzer is installed." >&2 + exit 1 + fi + + mkdir -p scan-build + + scan-build-14 \ + --force-analyze-debug-code \ + --status-bugs \ + -o ./scan-build/ \ + make --no-keep-going -j$(nproc --all) |& tee ./scan-build-result.txt + build_status=${PIPESTATUS[0]} + + if ! grep -siq "scan-build: No bugs found" ./scan-build-result.txt; then + echo "scan-build: bugs found!" + exit 1 + fi + + if [[ $build_status != "0" ]]; then + echo "scan-build: compilation failed!" + exit $build_status + fi + + ;; + *) + exit 1 + ;; + esac +} + +# Function to handle freeswitch installation +install_freeswitch() +{ + make install || exit 1 +} + +# Function to handle freeswitch validation +validate_freeswitch() +{ + local type="$1" + + case "$type" in + "unit-test") + exit 0 + ;; + "scan-build") + REPORT_PATH=$(find scan-build* -mindepth 1 -type d) + if [ -n "$REPORT_PATH" ]; then + echo "Found analysis report at: $REPORT_PATH" + + if command -v html2text > /dev/null 2>&1; then + echo "Report contents:" + html2text "$REPORT_PATH"/*.html || true + fi + + echo "Number of issues found:" + grep -c "