2020-07-02 16:53:33 +02:00
|
|
|
import os
|
2020-07-06 17:54:11 +02:00
|
|
|
import sys
|
2020-07-02 16:53:33 +02:00
|
|
|
import argparse
|
|
|
|
import json
|
2020-07-06 17:54:11 +02:00
|
|
|
from git import Repo
|
|
|
|
from git import Git
|
2020-07-07 14:34:19 +02:00
|
|
|
from pathlib import Path
|
2020-07-02 16:53:33 +02:00
|
|
|
|
2021-09-23 17:22:57 +02:00
|
|
|
repos=['sonar-abap','sonar-cpp','sonar-cobol','sonar-dotnet','sonar-css','sonar-flex','slang-enterprise','sonar-java','SonarJS','sonar-php','sonar-pli','sonar-plsql','sonar-python','sonar-rpg','sonar-swift','sonar-tsql','sonar-vb','sonar-html','sonar-xml','sonar-kotlin', 'sonar-secrets', 'sonar-security']
|
2020-07-02 16:53:33 +02:00
|
|
|
|
|
|
|
def load_json(file):
|
|
|
|
with open(file) as json_file:
|
2021-09-23 17:22:57 +02:00
|
|
|
return json.load(json_file)
|
2020-07-02 16:53:33 +02:00
|
|
|
|
2021-09-23 17:22:57 +02:00
|
|
|
# repoAndVersion uniquely identifies the analyzer and version implementing
|
|
|
|
# the rule for the given languages.
|
|
|
|
# Rule implementations for some langauges are spread across multiple repositories
|
|
|
|
# for example sonar-java and sonar-security for Java.
|
|
|
|
# We use repoAndVersion to avoid confusion between version of different analyzers.
|
|
|
|
def get_rules_json(path, languages, repoAndVersion):
|
|
|
|
print(f"Getting rules from {os.getcwd()} {path} for {repoAndVersion}")
|
2020-07-02 16:53:33 +02:00
|
|
|
for filename in os.listdir(path):
|
|
|
|
if filename.endswith(".json") and not filename.startswith("Sonar_way"):
|
|
|
|
rule=load_json(os.path.join(path, filename))
|
2021-09-23 17:22:57 +02:00
|
|
|
dump_rule(filename[:-5], rule, languages, repoAndVersion)
|
2020-07-02 16:53:33 +02:00
|
|
|
else:
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
2021-09-23 17:22:57 +02:00
|
|
|
def dump_rule(name, rule, languages, repoAndVersion):
|
2020-07-02 16:53:33 +02:00
|
|
|
if "compatibleLanguages" in rule:
|
|
|
|
for language in rule['compatibleLanguages']:
|
2021-09-23 17:22:57 +02:00
|
|
|
store_rule(name, rule, language, repoAndVersion)
|
2020-07-02 16:53:33 +02:00
|
|
|
else:
|
|
|
|
for language in languages:
|
2021-09-23 17:22:57 +02:00
|
|
|
store_rule(name, rule, language, repoAndVersion)
|
|
|
|
|
|
|
|
def store_rule(name, rule, language, repoAndVersion):
|
2020-07-06 17:54:11 +02:00
|
|
|
if language not in rules:
|
2020-07-02 16:53:33 +02:00
|
|
|
print(f"create entry for {language}")
|
2020-07-06 17:54:11 +02:00
|
|
|
rules[language] = {}
|
2020-07-09 16:11:40 +02:00
|
|
|
if '_' in name:
|
|
|
|
name=name[:name.find('_')]
|
2020-07-06 17:54:11 +02:00
|
|
|
if name not in rules[language]:
|
2021-09-23 17:22:57 +02:00
|
|
|
rules[language][name] = repoAndVersion
|
|
|
|
|
|
|
|
def dump_rules(repo, version):
|
2020-07-07 14:34:19 +02:00
|
|
|
for sp_file in Path('.').rglob('sonarpedia.json'):
|
|
|
|
print(sp_file)
|
|
|
|
sonarpedia_path=sp_file.parents[0]
|
2020-07-06 17:54:11 +02:00
|
|
|
sonarpedia = load_json(sp_file)
|
2021-09-23 17:22:57 +02:00
|
|
|
path=str(sonarpedia_path) + '/' + sonarpedia['rules-metadata-path'].replace('\\', '/')
|
2020-07-06 17:54:11 +02:00
|
|
|
languages=sonarpedia['languages']
|
2021-09-23 17:22:57 +02:00
|
|
|
get_rules_json(path, languages, repo + ' ' + version)
|
2020-07-06 17:54:11 +02:00
|
|
|
with open(f"../{rules_filename}", 'w') as outfile:
|
2021-09-23 17:22:57 +02:00
|
|
|
json.dump(rules, outfile, indent=2, sort_keys=True)
|
|
|
|
|
|
|
|
def checkout_repo(repo):
|
2021-05-31 17:05:54 +02:00
|
|
|
token=os.getenv('GITHUB_TOKEN')
|
|
|
|
if not token:
|
|
|
|
git_url=f"git@github.com:SonarSource/{repo}"
|
|
|
|
else:
|
2021-05-31 17:15:15 +02:00
|
|
|
git_url=f"https://{token}@github.com/SonarSource/{repo}"
|
2020-07-06 17:54:11 +02:00
|
|
|
git_repo=None
|
|
|
|
g=Git(repo)
|
|
|
|
if not os.path.exists(repo):
|
2021-09-23 17:22:57 +02:00
|
|
|
return Repo.clone_from(git_url, repo)
|
2020-07-06 17:54:11 +02:00
|
|
|
else:
|
2021-09-23 17:22:57 +02:00
|
|
|
return Repo(repo)
|
|
|
|
|
|
|
|
def scan_all_versions(repo):
|
|
|
|
git_repo = checkout_repo(repo)
|
2021-09-27 18:24:44 +02:00
|
|
|
versions = [tag.name for tag in git_repo.tags]
|
|
|
|
for version in versions:
|
|
|
|
if not '-' in version:
|
|
|
|
print(f"{repo} {version}")
|
|
|
|
scan_version(repo, version)
|
|
|
|
scan_version(repo, 'master')
|
2021-09-23 17:22:57 +02:00
|
|
|
|
2021-09-27 18:24:44 +02:00
|
|
|
def scan_version(repo, version):
|
2021-09-28 11:44:33 +02:00
|
|
|
r = checkout_repo(repo)
|
|
|
|
g = Git(repo)
|
2021-09-23 17:22:57 +02:00
|
|
|
os.chdir(repo)
|
|
|
|
try:
|
2021-09-28 11:44:33 +02:00
|
|
|
r.head.reference = r.commit(version)
|
|
|
|
r.head.reset(index=True, working_tree=True)
|
2020-07-07 10:12:56 +02:00
|
|
|
g.checkout(version)
|
2021-09-23 17:22:57 +02:00
|
|
|
dump_rules(repo, version)
|
2021-09-27 18:24:44 +02:00
|
|
|
except Exception as e:
|
|
|
|
print(f"{repo} {version} checkout failed, resetting and cleaning: {e}")
|
2021-09-23 17:22:57 +02:00
|
|
|
os.chdir('..')
|
|
|
|
|
2020-07-02 16:53:33 +02:00
|
|
|
def main():
|
|
|
|
parser = argparse.ArgumentParser(description='rules coverage')
|
2021-09-23 17:22:57 +02:00
|
|
|
parser.add_argument('command', nargs='+', help='see code for help')
|
2020-07-02 16:53:33 +02:00
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
global rules
|
|
|
|
global rules_filename
|
|
|
|
rules_filename='covered_rules.json'
|
|
|
|
if os.path.exists(rules_filename):
|
|
|
|
rules=load_json(rules_filename)
|
|
|
|
else:
|
|
|
|
rules={}
|
2021-09-23 17:22:57 +02:00
|
|
|
|
2020-07-07 11:00:33 +02:00
|
|
|
if args.command[0] == "batchall":
|
|
|
|
print(f"batch mode for {repos}")
|
|
|
|
for repo in repos:
|
2021-09-23 17:22:57 +02:00
|
|
|
scan_all_versions(repo)
|
2020-07-07 11:00:33 +02:00
|
|
|
elif args.command[0] == "batch":
|
|
|
|
repo=args.command[1]
|
|
|
|
print(f"batch mode for {repo}")
|
2021-09-23 17:22:57 +02:00
|
|
|
scan_all_versions(repo)
|
|
|
|
else:
|
2020-07-07 11:00:33 +02:00
|
|
|
repo=args.command[0]
|
2020-07-07 10:12:56 +02:00
|
|
|
version=args.command[1]
|
2020-07-07 11:00:33 +02:00
|
|
|
print(f"checking {repo} version {version}")
|
2021-09-27 18:24:44 +02:00
|
|
|
scan_version(repo, version)
|
2020-07-02 16:53:33 +02:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|