Sonar-scanner経由でCoverageアップロードする際の注意

pythonモジュールにおいて、SonarqubeにCoverageをアップロードしようとしたらハマった、ので、

## module構成
こんな感じ。pipenvもあるが、今回は関係ない。

```
root
├─ JenkinsFile                           ･･･ JenkinsFile
├─ sonar-project.properties              ･･･ SonarQube Scanner用設定ファイル
└─module                                 ･･･ module
    └─app                                 ･･･ アプリ用フォルダ
      ├─ .env                            ･･･ pipenv用環境変数定義ファイル
      ├─ Pipfile                         ･･･ pipenv用定義ファイル
      ├─.venv                            ･･･ 仮想環境(PIPENV_VENV_IN_PROJECT=1を設定した場合、ここに作成される)
      ├─src                              ･･･ ソースフォルダ
      └─test                             ･･･ テストソースフォルダ
```

## かんたんな前置き
JenkinsとSonarqube側両方に、Sonar-pythonのインストールも完了し、静的解析は問題なくアップロードできた。が、Sonarqube上、Coverageが表示されていないことがわかり、対応を行うことにした。

## Project側の修正
```sonar-project.properties
sonar.python.coverage.reportPath=**/app/coverage.xml
```
Coverageのありかを追加。

``` Pipfile.
coverage-report = "pytest -v --cov=src --cov-report=xml"
```
Coverage.xmlを出力するように変更

``` Jenkinsfile.
pipenv run coverage-report
```
Jenkinsからpipenv経由でレポートを出力するように変更。

## 出力されない…。

解析自体はうまくいっているようなのだが、SonarqubeにはReport出力されないので、debug開始。

- Coverage.xml →出力されている。
- 他の設定色々試す →変わりなし。
- sonarqube側の設定色々変えてみる →何も変わりなし。

というわけで、`sonar.log.level`をDEBUGに変更して、Jenkinsを再度実施してみると、以下になっている。

```
12:26:52.146 INFO: Python unit test coverage
12:26:52.146 DEBUG: Using pattern '**/app/coverage.xml' to find reports
12:26:52.268 INFO: Parsing report '/hogehoge/module/app/coverage.xml'
12:26:52.415 DEBUG: Cannot find the file 'calc.py', ignoring coverage measures
12:26:52.416 DEBUG: Cannot find the file 'main.py', ignoring coverage measures
```
pythonの当該ファイルが見つけられていない…。Coverage.xmlをみると

```Coverage.xml
 <sources>
  <source>/hogehoge/module/app/src</source>
 </sources>
 <packages>
  <package branch-rate="0" complexity="0" line-rate="0.6667" name=".">
   <classes>
    <class branch-rate="0" complexity="0" filename="calc.py" line-rate="0.8571" name="calc.py">
    <methods/>
```
sourceディレクトリは正しいようだが、どうもこれだとfilenameプロパティからのファイル名取得が実現できていないようだ。
## 結論

> I had similar issue and found the issue with paths in coverage.xml. After running SED (sed 's/filename\=\"/filename\=\"myprefix\//g' target/reports/coverage.xml), then sonar-runner published coverage report to SonarQube fine. Does anyone know whether sonar-runner has a fix for his yet? Ideally we should not need sed hacks in build. Sonar runner should recognise/resolve paths

https://stackoverflow.com/questions/18923204/sonar-python-coverage-report-issue

sonar-project.propertiesがある場所で、sonar-scannerを動作させるのだが、
どうやら、coverage.xmlに記載されているfilenameが上記からの相対パスで記載されていないとダメっぽい。

というわけで、JenkinsfileのCoverageファイル出力後の処理に以下の一行を追加

``` Jenkinsfile.
 sh "sed -i -e 's/filename\\="/filename\\="module\\/app\\/src\\//g' coverage.xml"
```

### 余談
> The triple-double-quote (""") string literal syntax allows for variable/expression substitution (interpolation), so the backslash (\) is interpreted as a special character "escape". Since the first open paren is not such a special character, Groovy compilation fails. If your intent is to have literal backslashes in the resulting string, you need to escape the backslashes. That is, use a double-backslash (\\) to substitute for one literal backslash.

https://stackoverflow.com/questions/40895903/jenkins-escape-sed-command
Jenkinsfile内でsedを利用する際には二重escapeが必要なんだよね。これいつも忘れるんだよなあ。

## 完了
これでSonarqube上でもCoverageが出力。やったね！

でもこれSonar-Scannerのバグのような気もするんだけどなあ…。