On 1/2/24 17:14, Eelco Chaudron wrote:
> 
> 
> On 2 Jan 2024, at 16:55, Ilya Maximets wrote:
> 
>> On 1/2/24 16:19, Eelco Chaudron wrote:
>>>
>>>
>>> On 2 Jan 2024, at 13:43, Ilya Maximets wrote:
>>>
>>>> On 12/20/23 16:07, Eelco Chaudron wrote:
>>>>>
>>>>>
>>>>> On 20 Dec 2023, at 11:19, Eelco Chaudron wrote:
>>>>>
>>>>>> This patch identifies new static analysis issues during a GitHub action
>>>>>> run and reports them. The process involves analyzing the changes 
>>>>>> introduced
>>>>>> in the current commit and comparing them to those in the preceding 
>>>>>> commit.
>>>>>>
>>>>>> However, there are two cases when the GitHub push action runner does not
>>>>>> provide enough details to determen the preceding commit. These cases are
>>>>>> a new branch or a forced push. The strategy for these exceptions is to
>>>>>> select the first commit not done by the current author as the base 
>>>>>> commit.
>>>>>
>>>>> Including Aarons comment on v3 into v4.
>>>>>
>>>>> +++ As an alternative we can look at the author (go back in time until
>>>>> +++ we find a different author), so if you’re lucky and it’s one of your
>>>>> +++ older patches you will be reminded again and again ;) Not sure if
>>>>> +++ this is easaly possible with a git command, but it might be worth
>>>>> +++ trying out.
>>>>>
>>>>> ++ I did some experiments with the above approach, and it seems to work
>>>>> ++  in all the use cases. The only problem could be that if you are also
>>>>> ++ the owner of a previous patch series, it might use a reference branch
>>>>> ++ too deep. This could potentially show issues not introduced by your
>>>>> ++ latest patches. But as you are still the author, you should be
>>>>> ++ “punished” for your earlier mistakes ;)
>>>>> ++
>>>>> ++ I’ll send out a v4, and we can continue the discussion there if needed 
>>>>> :)
>>>>>
>>>>> + I'll take a look after Jan 1, but I guess we might be able to check
>>>>> + against an upstream reference (for example, we can reference towards the
>>>>> + 'upstream' repository - such a reference does require some kind of
>>>>> + history being pulled) which we know should be stable and 'good'.  IE:
>>>>> + the script could add the OVS github remote if it doesn't already exist.
>>>>> + I think we could use that to find the common ancestor.  But I need to
>>>>> + dive into this more.
>>>>>
>>>>> I guess we can determine the origin branch going back, and then do 
>>>>> something like
>>>>> `git merge-base upstream/master HEAD` assuming we fetched the upstream 
>>>>> repository.
>>>>
>>>>
>>>> The 'determine the origin branch' is still tricky and requires some
>>>> guesswork in case of a new branch or a force push.  Maybe something
>>>> like listing all the heads in upstream repo and finding the one that
>>>> has the closest merge-base may be an option.  Then use that merge base
>>>> as a base commit to compare against.
>>>>
>>>> The merge-base with upstream/master will be a branching point for a
>>>> release branch, and that is way too far.
>>>
>>> ACK, I think going back in time till a different author will solve all this 
>>> for now.
>>> And this will even work in Ilya’s and my force commit workflow. So for now 
>>> I’ll keep
>>> it as it.
>>
>> It will not work in case you're incorporating someone else's patches in
>> your patch set, unless you're pushing them one by one.  Robot will catch
>> such problems, but people may miss.  Same problem if you are accumulating
>> multiple different patches before batch-applying them.
> 
> ACK, this is true. But with this patch in place, the robot should have 
> captured this for you ;)
> And your actual push to the main branch will also fail. Guess the previously 
> suggested patch -1
> will have the same problem.
> 
> Don’t think there will be a ‘full’ solution that will work in all cases 100% 
> of the time.

But why don't you like "closest merge-base against upstream heads" approach?
It seems less error prone to me.  At least I can't right away pinpoint a
simple scenario where it will do something unexpected, unless the branch is
completely diverged from anything upstream.

> This approach works for individual developers and the robot. For maintainers, 
> we can push the
> new branch, and then the actual patches, although making changes in the 
> middle might require
> deleting the remote branch, re-creating it, and re-apply. Tried this with 
> stgit, and this seems easy.
> 
> //Eelco
> 
>>>>> Both solutions will work, and I have no real preference.
>>>>>
>>>>> //Eelco
>>>>>
>>>>>> An example error output might look like this:
>>>>>>
>>>>>>   error level: +0 -0 no changes
>>>>>>   warning level: +2 +0
>>>>>>     New issue "deadcode.DeadStores Value stored to 'remote' is never 
>>>>>> read" (1 occurrence)
>>>>>>    file:///home/runner/work/ovs/ovs/vswitchd/ovs-vswitchd.c:86
>>>>>>     New issue "unix.Malloc Potential leak of memory pointed to by 
>>>>>> 'remote'" (1 occurrence)
>>>>>>    file:///home/runner/work/ovs/ovs/vswitchd/ovs-vswitchd.c:95
>>>>>>   note level: +0 -0 no changes
>>>>>>   all levels: +2 +0
>>>>>>
>>>>>> Signed-off-by: Eelco Chaudron <echau...@redhat.com>
>>>>>> ---
>>>>>>
>>>>>> changes in v2:
>>>>>>   - When it's a new branch, it compares it to the HEAD of the default 
>>>>>> branch.
>>>>>>
>>>>>> changes in v3:
>>>>>>   - Include the clang version as part of the cache
>>>>>>   - Change the way it looks for the 'default' branch so it will work
>>>>>>     for patch branches.
>>>>>>   - Also compare to the base branch for forced commits.
>>>>>>
>>>>>> changes in v4:
>>>>>>   - No longer look for a default branch, but consume all patches
>>>>>>     from the current author.
>>>>>>
>>>>>>  .ci/linux-build.sh                   |   29 ++++++++++
>>>>>>  .github/workflows/build-and-test.yml |  103 
>>>>>> ++++++++++++++++++++++++++++++++++
>>>>>>  2 files changed, 132 insertions(+)
>>>>>>
>>>>>> diff --git a/.ci/linux-build.sh b/.ci/linux-build.sh
>>>>>> index aa2ecc505..fedf1398a 100755
>>>>>> --- a/.ci/linux-build.sh
>>>>>> +++ b/.ci/linux-build.sh
>>>>>> @@ -49,6 +49,30 @@ function build_ovs()
>>>>>>      make -j4
>>>>>>  }
>>>>>>
>>>>>> +function clang_analyze()
>>>>>> +{
>>>>>> +    [ -d "./base-clang-analyzer-results" ] && cache_build=false \
>>>>>> +                                               || cache_build=true
>>>>>> +    if [ "$cache_build" = true ]; then
>>>>>> +        # If this is a cache build, proceed to the base branch's 
>>>>>> directory.
>>>>>> +        cd base_ovs_main
>>>>
>>>> pushd/popd might be better here.
>>>
>>> ACK will do this next revision.
>>>>
>>>>>> +    fi;
>>>>>> +
>>>>>> +    configure_ovs $OPTS
>>>>>> +    make clean
>>>>>> +    scan-build -o ./clang-analyzer-results -sarif --use-cc=clang make 
>>>>>> -j4
>>>>
>>>> We have a make target for clang-analyze and it depends on the clean 
>>>> already.
>>>> Maybe we can extend it to accept custom arguments via env variable and pass
>>>> the '-sarif' this way?  E.g. make clang-analyze 
>>>> SCAN_BUILD_OPTIONS="-sarif".
>>>
>>> Let me look into this, as I like the idea.
>>>
>>>> Also, -j4 should be changed to ${JOBS} since that patch got merged.
>>>
>>> ACK
>>>
>>>> And we have CC defined in the job description, so should not use clang 
>>>> directly.
>>>
>>> ACK
>>>
>>>>>> +
>>>>>> +    if [ "$cache_build" = true ]; then
>>>>>> +        # Move results, so it will be picked up by the cache.
>>>>>> +        mv ./clang-analyzer-results ../base-clang-analyzer-results
>>>>>> +        cd ..
>>>>>> +    else
>>>>>> +        # Only do the compare on the none cache builds.
>>>>>> +        sarif --check note diff ./base-clang-analyzer-results \
>>>>>> +                                ./clang-analyzer-results
>>>>>> +    fi;
>>>>>> +}
>>>>>> +
>>>>>>  if [ "$DEB_PACKAGE" ]; then
>>>>>>      ./boot.sh && ./configure --with-dpdk=$DPDK && make debian
>>>>>>      mk-build-deps --install --root-cmd sudo --remove debian/control
>>>>>> @@ -116,6 +140,11 @@ fi
>>>>>>
>>>>>>  OPTS="${EXTRA_OPTS} ${OPTS} $*"
>>>>>>
>>>>>> +if [ "$CLANG_ANALYZE" ]; then
>>>>>> +    clang_analyze
>>>>>> +    exit 0
>>>>>> +fi
>>>>>> +
>>>>>>  if [ "$TESTSUITE" = 'test' ]; then
>>>>>>      # 'distcheck' will reconfigure with required options.
>>>>>>      # Now we only need to prepare the Makefile without sparse-wrapped 
>>>>>> CC.
>>>>>> diff --git a/.github/workflows/build-and-test.yml 
>>>>>> b/.github/workflows/build-and-test.yml
>>>>>> index 09654205e..cb277ff43 100644
>>>>>> --- a/.github/workflows/build-and-test.yml
>>>>>> +++ b/.github/workflows/build-and-test.yml
>>>>>> @@ -223,6 +223,109 @@ jobs:
>>>>>>          name: logs-linux-${{ join(matrix.*, '-') }}
>>>>>>          path: logs.tgz
>>>>>>
>>>>>> +  build-clang-analyze:
>>>>>> +    needs: build-dpdk
>>>>>> +    env:
>>>>>> +      dependencies: |
>>>>>> +        automake bc clang-tools libbpf-dev libnuma-dev libpcap-dev \
>>>>>> +        libunbound-dev libunwind-dev libssl-dev libtool llvm-dev \
>>>>>> +        python3-unbound
>>>>
>>>> Do we need a python3-unbound?
>>>
>>> Added it, as I removed the 32-bit conditional install, but can verify if it 
>>> fails without.
>>>
>>>>>> +      CC:   clang
>>>>>> +      DPDK: dpdk
>>>>>> +      CLANG_ANALYZE: true
>>>>>> +    name: clang-analyze
>>>>>> +    runs-on: ubuntu-22.04
>>>>>> +    timeout-minutes: 30
>>>>>> +
>>>>>> +    steps:
>>>>>> +    - name: checkout
>>>>>> +      uses: actions/checkout@v3
>>>>>> +      with:
>>>>>> +        fetch-depth: 0
>>>>>> +
>>>>>> +    - name: get base branch sha
>>>>>> +      id: base_branch
>>>>>> +      env:
>>>>>> +        BASE_SHA: ${{ github.event.pull_request.base.sha }}
>>>>>> +        EVENT_BEFORE: ${{ github.event.before }}
>>>>>> +        FORCED_PUSH: ${{ github.event.forced }}
>>>>>> +      run: |
>>>>>> +        if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
>>>>>> +          echo "sha=$BASE_SHA" >> $GITHUB_OUTPUT
>>>>>> +        else
>>>>>> +          if [ "$EVENT_BEFORE" = 
>>>>>> "0000000000000000000000000000000000000000" ] \
>>>>>> +             || [ "$FORCED_PUSH" = true ]; then
>>>>>> +            echo "sha=$(git log --pretty=format:"%H %ae" | \
>>>>>> +                        grep -m1 -v $(git log -1 --pretty=format:"%ae") 
>>>>>> | \
>>>>>> +                        awk '{print $1}')" >> $GITHUB_OUTPUT
>>>>>> +          else
>>>>>> +            echo "sha=$EVENT_BEFORE" >> $GITHUB_OUTPUT
>>>>>> +          fi
>>>>>> +        fi
>>>>>> +
>>>>>> +    - name: checkout base branch
>>>>>> +      uses: actions/checkout@v3
>>>>>> +      with:
>>>>>> +        ref: ${{ steps.base_branch.outputs.sha }}
>>>>>> +        path: base_ovs_main
>>>>>> +
>>>>>> +    - name: update PATH
>>>>>> +      run: |
>>>>>> +        echo "$HOME/bin"        >> $GITHUB_PATH
>>>>>> +        echo "$HOME/.local/bin" >> $GITHUB_PATH
>>>>>> +
>>>>>> +    - name: generate cache key
>>>>>> +      id: cache_key
>>>>>> +      run: |
>>>>>> +        ver=$(clang -v 2>&1 | grep version | \
>>>>
>>>> s/clang/${CC}/ ?
>>>>
>>>> And if we grep for ' version ', the check will work for gcc as well,
>>>> even if we do not really care about this case. :)
>>>
>>> ACK, will make the change below as well.
>>>
>>>>>> +              sed 's/.*version \([0-9]*\.[0-9]*\.[0-9]*\).*/\1/g')
>>>>>> +        echo "key=clang-${ver}-analyze-$(git -C base_ovs_main rev-parse 
>>>>>> HEAD)" \
>>>>>> +          >> $GITHUB_OUTPUT
>>>>>> +
>>>>>> +    - name: check for analyzer result cache
>>>>>> +      id: clang_cache
>>>>>> +      uses: actions/cache@v3
>>>>>> +      with:
>>>>>> +        path: base-clang-analyzer-results
>>>>>> +        key:  ${{ steps.cache_key.outputs.key }}
>>>>>> +
>>>>>> +    - name: set up python
>>>>>> +      uses: actions/setup-python@v4
>>>>>> +      with:
>>>>>> +        python-version: '3.9'
>>>>>> +
>>>>>> +    - name: get cached dpdk-dir
>>>>>> +      uses: actions/cache/restore@v3
>>>>>> +      with:
>>>>>> +        path: dpdk-dir
>>>>>> +        key:  ${{ needs.build-dpdk.outputs.dpdk_key }}
>>>>>> +
>>>>>> +    - name: update APT cache
>>>>>> +      run:  sudo apt update || true
>>>>>> +
>>>>>> +    - name: install common dependencies
>>>>>> +      run:  sudo apt install -y ${{ env.dependencies }}
>>>>>> +
>>>>>> +    - name: install sarif tools
>>>>>> +      run: sudo pip3 install --disable-pip-version-check sarif-tools
>>>>
>>>> '--user' to avoid sudo.  Might also be better to add this to the
>>>> existing command in the linux-prepare script instead to allow pip
>>>> to choose compatible versions of all the packages.
>>>
>>> Let me move it to see if this will work.
>>>
>>>>>> +
>>>>>> +    - name: prepare
>>>>>> +      run:  ./.ci/linux-prepare.sh
>>>>>> +
>>>>>> +    - name: build base reference
>>>>>> +      if: steps.clang_cache.outputs.cache-hit != 'true'
>>>>>> +      run:  ./.ci/linux-build.sh
>>>>>> +
>>>>>> +    - name: build
>>>>>> +      run:  ./.ci/linux-build.sh
>>>>>> +
>>>>>> +    - name: save cache
>>>>>> +      uses: actions/cache/save@v3
>>>>>> +      if: always() && steps.clang_cache.outputs.cache-hit != 'true'
>>>>
>>>> So, we will save the cache even if the build of the base reference failed?
>>>> Maybe move this before the 'build' stage and remove the 'always()' check?
>>>
>>> Good catch, will move it up.
>>>
>>>>>> +      with:
>>>>>> +        path: base-clang-analyzer-results
>>>>>> +        key:  ${{ steps.cache_key.outputs.key }}
>>>>>> +
>>>>>>    build-osx:
>>>>>>      env:
>>>>>>        CC:    clang
>>>>>>
>>>>
>>>> Best regards, Ilya Maximets.
>>>
>>> Thanks for the comments, will prep a v5.
>>>
>>> //Eelco
>>>
> 

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to