[action] add daily check routine
authorYelin Jeong <yelini.jeong@samsung.com>
Fri, 3 Mar 2023 06:12:33 +0000 (15:12 +0900)
committer추지호/NPU Lab(SR)/삼성전자 <jiho.chu@samsung.com>
Thu, 16 Mar 2023 02:21:56 +0000 (11:21 +0900)
This patch adds daily-check action.
gen_badge.py is from local CI server.

Signed-off-by: Yelin Jeong <yelini.jeong@samsung.com>
.ahub/sam/build.sh [new file with mode: 0755]
.github/gen_badge.py [new file with mode: 0644]
.github/workflows/daily-check.yml [new file with mode: 0644]
.github/workflows/pr-build-aarch64.yml

diff --git a/.ahub/sam/build.sh b/.ahub/sam/build.sh
new file mode 100755 (executable)
index 0000000..a44dcab
--- /dev/null
@@ -0,0 +1,5 @@
+export INSTALL_PREFIX=/opt/trinity
+export PKG_CONFIG_PATH=${INSTALL_PREFIX}/lib/pkgconfig
+
+CFLGAS="-g -O0" meson --buildtype=plain --prefix=${INSTALL_PREFIX} --sysconfdir=${INSTALL_PREFIX}/etc --libdir=lib --bindir=bin --includedir=include build -Denable_npu_emul=true -Denable_data_manip=true -Db_coverage=true
+ninja -C build
diff --git a/.github/gen_badge.py b/.github/gen_badge.py
new file mode 100644 (file)
index 0000000..00132aa
--- /dev/null
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+
+##
+# Copyright (C) 2020 Samsung Electronics
+# License: Apache-2.0
+#
+# @file gen_badge.py
+# @brief A tool for generating a github badge image in svg format
+# @author Wook Song <wook16.song@samsung.com>
+#         Dongju Chae <dongju.chae@samsung.com>
+#         Gichan Jang <gichan2.jang@samsung.com>
+
+import os
+import sys
+import requests
+from bs4 import BeautifulSoup
+import xml.etree.ElementTree as elemTree
+
+# shields local server (https://github.com/badges/shields)
+shields_url = "http://localhost:8080"
+
+##
+# @brief Generate a github badge svg file representing daily build result
+def gen_badge(label, message, color, path):
+    print("gen badge")
+    url_str = shields_url + '/badge/' + label+'-' + message + '-' + color
+    print('Target url : ' + url_str)
+    res = requests.get(url_str)
+    with open(path, "w") as file:
+        file.write(str(res.text))
+
+##
+# @brief Generate a github badge svg file representing code coverage
+# @param[in] html A concatenated string of the whole contents in index.html that is the result
+# @param[in] path A file path to save the svg file
+# @param[in] tool The name of analyzer
+def gen_coverage_badge(html, path, tool = "lcov"):
+    print("code coverage")
+    soup = BeautifulSoup(html, 'html.parser')
+
+    if tool == "gcovr":
+      parsed = soup.find('table').find_all('td', {'class' : 'headerTableEntry'})
+    else:
+      parsed = soup.find('table').find_all('td', {'class' : 'headerCovTableEntry'})
+
+    line_hits = float(parsed[0].text)
+    lines = float(parsed[1].text)
+
+    line_coverage = line_hits / lines
+    print line_coverage
+
+    if line_coverage > 0.8:
+      gen_badge ('Coverage', format(line_coverage, "2.1%"), '00b000', path)
+    elif line_coverage > 0.7:
+      gen_badge ('Coverage', format(line_coverage, "2.1%"), 'green', path)
+    elif line_coverage > 0.6:
+      gen_badge ('Coverage', format(line_coverage, "2.1%"), 'yellogreen', path)
+    elif line_coverage > 0.5:
+      gen_badge ('Coverage', format(line_coverage, "2.1%"), 'yello', path)
+    elif line_coverage > 0.4:
+      gen_badge ('Coverage', format(line_coverage, "2.1%"), 'orange', path)
+    else:
+      gen_badge ('Coverage', format(line_coverage, "2.1%"), 'red', path)
+
+def gen_unittest_badge(dir_xml, path):
+    num_total = 0
+    num_pos = 0
+    num_neg = 0
+
+    for f in os.listdir(dir_xml):
+        if f.endswith(".xml"):
+            tree = elemTree.parse(dir_xml + '/' + f)
+
+            testsuite = tree.find('./testsuite')
+            for testcase in testsuite.iter("testcase"):
+                name = testcase.attrib["name"]
+                if name.endswith ('_n'):
+                    num_neg = num_neg + 1
+                else:
+                    num_pos = num_pos + 1
+
+    num_total = num_pos + num_neg
+    str_unittest = str(num_total) + ' (' + str(num_pos) + ' + ' + str(num_neg) + ')'
+
+    neg_rate = (float(num_neg)/float(num_total)) * 100.0
+    print neg_rate
+
+    if neg_rate > 70.0:
+      gen_badge ('Unittest', str_unittest, '00b000', path)
+    elif neg_rate > 60.0:
+      gen_badge ('Unittest', str_unittest, 'green', path)
+    elif neg_rate > 50.0:
+      gen_badge ('Unittest', str_unittest, 'yellogreen', path)
+    elif neg_rate > 40.0:
+      gen_badge ('Unittest', str_unittest, 'yello', path)
+    elif neg_rate > 30.0:
+      gen_badge ('Unittest', str_unittest, 'orange', path)
+    else:
+      gen_badge ('Unittest', str_unittest, 'red', path)
+
+def gen_samscore_badge(score, path):
+    score = float(score)
+    print score
+
+    if score == 5.0:
+      gen_badge ('SAM Score', format(score, "1.2f"), '00b000', path)
+    elif score > 4.0:
+      gen_badge ('SAM Score', format(score, "1.2f"), 'green', path)
+    elif score > 3.0:
+      gen_badge ('SAM Score', format(score, "1.2f"), 'yello', path)
+    else:
+      gen_badge ('SAM Score', format(score, "1.2f"), 'red', path)
+
+def gen_version_badge(version, path):
+    print version
+
+    gen_badge ('Version', 'v' + version, 'blue', path)
+
+def gen_issues_badge(issues, path):
+    print issues
+
+    gen_badge ('Issues', issues + ' open', 'yellow', path)
+
+def gen_pulls_badge(pulls, path):
+    print pulls
+
+    gen_badge ('Pull Requests', pulls + ' open', 'yellow', path)
+
+if __name__ == '__main__':
+    # argv[1]: [badgetype] a string indicating the type of badge, 'codecoverage'
+    # argv[2]: [url/file] a path or url of LCOV html to get information for badge generation
+    # argv[3]: [file] a file path to save the generated svg file
+    if len(sys.argv) < 4:
+      exit(1)
+
+    badgetype = 'unknown'
+    for each_badge_type in ['codecoverage','unittest','samscore','version','issues','pulls']:
+        if sys.argv[1].lower() == each_badge_type:
+            badgetype = sys.argv[1].lower()
+    print(badgetype)
+    if badgetype == 'unknown':
+        exit(1)
+
+    path_out_svg=''
+    if not os.access(os.path.dirname(sys.argv[3]) or os.getcwd(), os.W_OK):
+        exit(1)
+    else:
+        path_out_svg = os.path.abspath(sys.argv[3])
+        if os.path.isdir(path_out_svg) or os.path.islink(path_out_svg):
+            exit(1)
+    print(path_out_svg)
+    if badgetype == 'codecoverage':
+        str_html = ''
+        print(sys.argv[2])
+        if os.path.isfile(sys.argv[2]):
+            with open(sys.argv[2], 'r') as f:
+                str_html = f.read()
+                if not BeautifulSoup(str_html, "html.parser").find():
+                    exit(1)
+        elif sys.argv[2].startswith('http'):
+            str_html = get_html(sys.argv[2])
+            if str_html == '':
+                exit(2)
+        else:
+            exit(3)
+
+        gen_coverage_badge(str_html, path_out_svg)
+    elif badgetype == 'unittest':
+        gen_unittest_badge(sys.argv[2], path_out_svg)
+    elif badgetype == 'samscore':
+        gen_samscore_badge(sys.argv[2], path_out_svg)
+    elif badgetype == 'version':
+        gen_version_badge(sys.argv[2], path_out_svg)
+    elif badgetype == 'issues':
+        gen_issues_badge(sys.argv[2], path_out_svg)
+    elif badgetype == 'pulls':
+        gen_pulls_badge(sys.argv[2], path_out_svg)
diff --git a/.github/workflows/daily-check.yml b/.github/workflows/daily-check.yml
new file mode 100644 (file)
index 0000000..e09d7f2
--- /dev/null
@@ -0,0 +1,107 @@
+name: check coverage and update badges daily
+
+on:
+  schedule:
+    # scheduled workflow run on the latest commit on the default or base
+    # branch.
+    - cron: '00 01 * * 0-5'
+
+env:
+  BART_ID: ${{ secrets.BART_ID }}
+  BART_PW: ${{ secrets.BART_PW }}
+
+jobs:
+  daily-check:
+    runs-on: [ code-large ]
+    container:
+      image: aip-docker-local.bart.sec.samsung.net/n2s2_docker/bionic:latest
+      # for chroot-based build system
+      options: --privileged
+      credentials:
+        username: ${{ secrets.BART_ID }}
+        password : ${{ secrets.BART_PW }}
+
+    timeout-minutes: 60
+
+    steps:
+      - name: Clone your repository
+        uses: CODE-Actions/checkout@v2
+
+      - name: Create badges folder
+        run:
+          mkdir ~/badges
+        shell: bash
+
+      - name: Setup shields local server to create badges
+        run: |
+          git clone https://github.com/badges/shields.git
+          cd shields
+          git checkout $(git tag | grep server | tail -n 1) # checkout the latest tag
+          export NODE_TLS_REJECT_UNAUTHORIZED=0
+          npm i --legacy-peer-deps
+          npm run start &
+          sleep 30 # waif for server ready
+        shell: bash
+
+      - name: Coverage check
+        run: |
+          bash utils/coverage/coverage.sh lcov
+          cp -r utils/coverage/coverage_result coverage_result
+
+          python2 $GITHUB_WORKSPACE/.github/actions/create-badge/gen_badge.py codecoverage coverage_result/index.html ~/badges/codecoverage.svg
+          python2 $GITHUB_WORKSPACE/.github/actions/create-badge/gen_badge.py unittest build/tests/unittests/ ~/badges/unittest.svg
+        shell : bash
+
+      - name: Upload coverage result
+        uses: CODE-Actions/upload-artifact@v2
+        with:
+          name: coverage_result
+          path: coverage_result
+
+      - name: Get SAM Score
+        run: |
+          export SAM_HOME=/root/sam/SAM_v7.1.7-linux/
+          export PATH=$PATH:/$SAM_HOME/bin
+          rm -rf build
+
+          sam init
+          sam scan --language AUTO_C_CPP $GITHUB_WORKSPACE/.ahub/sam/build.sh \
+                  -exclude $GITHUB_WORKSPACE/.ahub/sam/exclude.txt
+          sam analyze --language auto_c_cpp
+          sam calculate --language auto_c_cpp >> log.out
+
+          SAM_SCORE=`cat log.out | grep "Score -" | awk '{print $9}'`
+          echo $SAM_SCORE
+
+          python2 $GITHUB_WORKSPACE/.github/actions/create-badge/gen_badge.py samscore $SAM_SCORE ~/badges/samscore.svg
+
+      - name: Create badges
+        run: |
+          VERSION=`cat packaging/npu-engine.spec | grep Version | awk '{print $2}'`
+          echo $VERSION
+          python2 $GITHUB_WORKSPACE/.github/actions/create-badge/gen_badge.py version $VERSION ~/badges/version.svg
+
+          NUM_PULLS=`curl -u "${{ secrets.GIT_ID }}:${{ secrets.GIT_PW }}" https://github.sec.samsung.net/api/v3/repos/AIP/NPU_SystemService/pulls?state=open 2>/dev/null | jq length`
+          NUM_ISSUES=`curl -u "${{ secrets.GIT_ID }}:${{ secrets.GIT_PW }}" https://github.sec.samsung.net/api/v3/repos/AIP/NPU_SystemService/issues?state=open 2>/dev/null | jq length`
+          NUM_ISSUES=$(($NUM_ISSUES-$NUM_PULLS))
+
+          echo $NUM_PULLS
+          echo $NUM_ISSUES
+
+          python2 $GITHUB_WORKSPACE/.github/actions/create-badge/gen_badge.py pulls $NUM_PULLS ~/badges/pulls.svg
+          python2 $GITHUB_WORKSPACE/.github/actions/create-badge/gen_badge.py issues $NUM_ISSUES ~/badges/issues.svg
+        shell: bash
+
+      - name: Upload badges
+        run: |
+          git config --global user.name "${{ secrets.GIT_ID }}"
+          git config --global user.email "${{ secrets.GIT_EMAIL }}"
+
+          git clone https://${{ secrets.GIT_ID }}:${{ secrets.GIT_PW }}@github.sec.samsung.net/nnsuite/n2s2.git
+          cd n2s2
+
+          git remote set-url origin https://${{ secrets.GIT_ID }}:${{ secrets.GIT_PW }}@github.sec.samsung.net/nnsuite/n2s2.git
+          mv ~/badges/* AIP_NPU_SystemService/badges
+          git add .
+          git commit -s -m "Update the badges for NPU_SystemService"
+          git push --set-upstream origin master
index 1b57c12814aa95a062b0fbe78851a9f64a7be4df..156357942d0c500f46b553f8deec6d1bbabf0c6f 100644 (file)
@@ -1,7 +1,6 @@
 name: build package for aarch64
 
 on:
-  push:
   pull_request_target:
     branches: [ tizen ]