diff --git a/scripts/check-ci-job-skippability.js b/scripts/check-ci-job-skippability.js deleted file mode 100755 index a351a88a1..000000000 --- a/scripts/check-ci-job-skippability.js +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env node - -console.log("DISABLED — https://github.com/mapbox/mapbox-gl-native-ios/issues/19") -process.exit(0) - -/* -This script takes two parameters or three environment variables: - - {CI job name|$CIRCLE_JOB} {SHA1...SHA1|$CIRCLE_MERGE_BASE...$CIRCLE_SHA1} - -The flow of this script: - - - List of files changed in PR: `git diff --name-only start...end` - - Extract list into array. - - Remove items from array if they match: - - Global ignore list. - - Other platform ignore lists. - - If array still contains items, do not authorize skipping CI job. - - Else if array is empty, skip CI job. - -To add support for a new platform: - - - Add a new PLATFORM_FILES array with a list of unique paths for the - files belonging to the platform. - - Add a case to `skippableFilePatternsForCIJob()` with: - - The prefix for the platform's CI job names. - - A concatenated array of other platform paths that are safe to ignore - for the new platform. These should be files that can change without - having any effect on the output of the new platform. - - Update other cases in `skippableFilePatternsForCIJob()` to include the - paths for the new platform. -*/ - -const execSync = require('child_process').execSync; -const _ = require('lodash'); -const minimatch = require("minimatch"); - -console.step = _.partial(console.log, '\n\033[1m\033[36m*', _, '\033[0m'); - -// BUILD PARAMETERS -const CI_JOB_NAME = process.argv[2] || process.env.CIRCLE_JOB; -if (!CI_JOB_NAME) { console.error('You must specify the name of a CI job as a parameter or environment variable.'); process.exit(1); } - -const COMMIT_RANGE = process.argv[3] || `${process.env.CIRCLE_MERGE_BASE}...${process.env.CIRCLE_SHA1}`; -if (!COMMIT_RANGE || COMMIT_RANGE.includes('undefined')) { console.error('You must specify a range of commits to check for changed files in as a parameter or environment variable.'); process.exit(1); } - -// FILE SKIPPING PATTERNS -const ALWAYS_SKIPPABLE_FILES = [ - '**/CHANGELOG.md', - '**/README.md', - '**/CONTRIBUTING.md', - '**/DEVELOPING.md', - '**/INSTALL.md', - '**/*.podspec' -] - -const ANDROID_FILES = [ - 'platform/android/**' -] - -const DARWIN_FILES = [ - 'platform/darwin/**' -] - -const IOS_FILES = [ - 'platform/ios/**' -] - -const MACOS_FILES = [ - 'platform/macos/**' -] - -const OTHER_PLATFORMS = [ - 'platform/glfw/**', - 'platform/linux/**', - 'platform/node/**', - 'platform/qt/**', - 'benchmark/**', - 'test/**' -] - -function skippableFilePatternsForCIJob(job) { - if (job.includes('render-tests')) { - // Render tests run on specific platforms are effectively unskippable core jobs, not platform jobs. - return ALWAYS_SKIPPABLE_FILES; - } else if (job.startsWith('ios')) { - return _.concat(ALWAYS_SKIPPABLE_FILES, ANDROID_FILES, MACOS_FILES, OTHER_PLATFORMS); - } else if (job.startsWith('android')) { - return _.concat(ALWAYS_SKIPPABLE_FILES, DARWIN_FILES, IOS_FILES, MACOS_FILES, OTHER_PLATFORMS); - } else if (job.startsWith('macos')) { - return _.concat(ALWAYS_SKIPPABLE_FILES, ANDROID_FILES, IOS_FILES, OTHER_PLATFORMS); - } else { - return ALWAYS_SKIPPABLE_FILES; - } -} - -console.step(`Getting list of files changed between ${COMMIT_RANGE}`); - -let changedFiles = execSync(`git diff --name-only ${COMMIT_RANGE}`).toString().split('\n'); -changedFiles = _.compact(changedFiles); - -console.log(`${changedFiles.length} file${changedFiles.length == 1 ? '':'s'} changed.`); - -console.step(`Checking changed files for paths relevant to ${CI_JOB_NAME} job`); - -// Filter the changed files array to remove files that are irrelevant to the specified CI job. -_.remove(changedFiles, function(changedFile) { - for (const skippableFilePattern of skippableFilePatternsForCIJob(CI_JOB_NAME)) { - if (minimatch(changedFile, skippableFilePattern, { dot: true, nocase: true })) { - return true; - } - } - return false; -}); - -if (changedFiles.length) { - console.log(`Found ${changedFiles.length} unskippable changed file${changedFiles.length == 1 ? '':'s'}:\n`, changedFiles); -} else { - console.log(`Found no relevant changed files, so it's safe to skip the remainder of this CI job.`) - if (process.env.CIRCLECI) { - console.step('Aborting CI job'); - execSync(`circleci step halt`, {stdio: 'inherit'}); - } -} diff --git a/scripts/check-qt.sh b/scripts/check-qt.sh deleted file mode 100755 index 578003824..000000000 --- a/scripts/check-qt.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -o pipefail - -if [ ! $(command -v qmake 2> /dev/null) ]; then - echo "No qmake found - missing Qt development files" - exit 1 -fi diff --git a/scripts/check-sha256.ps1 b/scripts/check-sha256.ps1 deleted file mode 100644 index e551605ad..000000000 --- a/scripts/check-sha256.ps1 +++ /dev/null @@ -1,7 +0,0 @@ -param([string]$file, [string]$hash); - -$hashFromFile = Get-FileHash -Path $file -Algorithm SHA256 - -if ($hashFromFile.Hash -ne $hash) { - Throw 'Hash mismatch!' -} diff --git a/scripts/check_binary_size.js b/scripts/check_binary_size.js deleted file mode 100755 index 73d6ab750..000000000 --- a/scripts/check_binary_size.js +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env node - -const jwt = require('jsonwebtoken'); -const github = require('@octokit/rest').plugin(require('@octokit/plugin-retry'))({ - retry: { doNotRetry: [ /* Empty — retry on any error code. */ ] } -}) -const prettyBytes = require('pretty-bytes'); -const fs = require('fs'); - -const SIZE_CHECK_APP_ID = 14028; -const SIZE_CHECK_APP_INSTALLATION_ID = 229425; - -const file = process.argv[2]; -const label = process.argv[3]; -const {size} = fs.statSync(file); -const name = `Size - ${label}`; - -process.on('unhandledRejection', error => { - console.log(error); - process.exit(1) -}); - -const pk = process.env['SIZE_CHECK_APP_PRIVATE_KEY']; -if (!pk) { - console.log('Fork PR; not computing size.'); - process.exit(0); -} - -const key = Buffer.from(pk, 'base64').toString('binary'); -const payload = { - exp: Math.floor(Date.now() / 1000) + 60, - iat: Math.floor(Date.now() / 1000), - iss: SIZE_CHECK_APP_ID -}; - -const token = jwt.sign(payload, key, {algorithm: 'RS256'}); -github.authenticate({type: 'app', token}); - -function getPriorSize() { - const mergeBase = process.env['CIRCLE_MERGE_BASE']; - if (!mergeBase) { - console.log('No merge base available.'); - return Promise.resolve(null); - } - - return github.checks.listForRef({ - owner: 'mapbox', - repo: 'mapbox-gl-native', - ref: mergeBase - }).then(({data}) => { - const run = data.check_runs.find(run => run.name === name); - if (!run) { - console.log('No matching check found.'); - return Promise.resolve(null); - } - return +run.output.summary.match(/`.*` is (\d+) bytes/)[1]; - }); -} - -github.apps.createInstallationToken({installation_id: SIZE_CHECK_APP_INSTALLATION_ID}) - .then(({data}) => { - github.authenticate({type: 'token', token: data.token}); - getPriorSize().then(prior => { - const title = (() => { - if (prior) { - const change = size - prior; - const percent = (change / prior) * 100; - return `${change >= 0 ? '+' : ''}${prettyBytes(change)} ${percent.toFixed(3)}% (${prettyBytes(size)})`; - } else { - return prettyBytes(size); - } - })(); - - console.log(`${label}: ${title} (${size} bytes)`); - - return github.checks.create({ - owner: 'mapbox', - repo: 'mapbox-gl-native', - name: `Size - ${label}`, - head_branch: process.env['CIRCLE_BRANCH'], - head_sha: process.env['CIRCLE_SHA1'], - status: 'completed', - conclusion: 'success', - completed_at: new Date().toISOString(), - output: { - title, - summary: `\`${file}\` is ${size} bytes (${prettyBytes(size)})` - } - }); - }) - }); diff --git a/scripts/ci-circleci-start-pipeline.py b/scripts/ci-circleci-start-pipeline.py deleted file mode 100755 index bcd1134a1..000000000 --- a/scripts/ci-circleci-start-pipeline.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python3 - -# Implements https://circleci.com/docs/api/v2/#trigger-a-new-pipeline - -import argparse -import os -import requests -import sys - - -def TriggerPiperline(slug, token, branch, params): - url = "https://circleci.com/api/v2/project/github/%s/pipeline" % (slug) - - headers = { - "Content-Type": "application/json", - "Accept": "application/json", - } - - data = { - "parameters": params - } - - if branch: - data["branch"] = branch - - r = requests.post(url, auth=(token, ""), headers=headers, json=data) - - if r.status_code != 201 and r.status_code != 200: - print("Error triggering the CircleCI: %s." % r.json()["message"]) - sys.exit(1) - - -def Main(): - token = os.getenv("CIRCLE_API_TOKEN") - hash = os.getenv("CIRCLE_SHA1", default="1234567890") - username = os.getenv("CIRCLE_PROJECT_USERNAME", default="username") - project = os.getenv("CIRCLE_PROJECT_REPONAME", default="repository") - - parser = argparse.ArgumentParser( - description="Creates CircleCI jobs and waits for the result.") - - parser.add_argument("--token", default=token, - help="CircleCI token, otherwise environment CIRCLE_API_TOKEN.") - parser.add_argument("--origin-slug", default="mapbox/mapbox-gl-native", - help="Origin repository, otherwise CIRCLE_PROJECT_USERNAME/CIRCLE_PROJECT_REPONAME.") - parser.add_argument("--target-slug", default="".join((username, '/', project)), - help="Repository to trigger the pipeline, example: mapbox/mapbox-gl-native-internal.") - parser.add_argument("--hash", default=hash, - help="Commit git hash that triggered the pipeline, otherwise environment CIRCLE_SHA1.") - parser.add_argument("--branch", - help="Build a specific branch, otherwise it will build the default branch.") - - args = parser.parse_args() - - if not args.token: - print("CircleCI token not set. Use --token or set CIRCLE_API_TOKEN.") - sys.exit(1) - - params = { - "mapbox_upstream": True, - "mapbox_slug": args.origin_slug, - "mapbox_hash": args.hash - } - - TriggerPiperline(args.target_slug, args.token, args.branch, params) - - return 0 - - -if __name__ == "__main__": - Main() diff --git a/scripts/ci/Dockerfile b/scripts/ci/Dockerfile deleted file mode 100644 index 465c4ac64..000000000 --- a/scripts/ci/Dockerfile +++ /dev/null @@ -1,133 +0,0 @@ -FROM ubuntu:eoan-20200313 - -ENV DEBIAN_FRONTEND="noninteractive" -ENV ANDROID_HOME="/opt/android" - -WORKDIR /src - -# Use faster mirrors from Finland -COPY etc/apt/sources.list /etc/apt - -RUN set -eu \ - && apt-get update \ - && apt-get dist-upgrade -y \ - && apt-get autoremove --purge -y && apt-get clean - -# CI requirements -RUN set -eu && apt-get install -y \ - ca-certificates \ - git \ - gzip \ - ssh \ - tar \ - colorized-logs \ - python-scipy \ - && apt-get autoremove --purge -y && apt-get clean - -# Base dependencies -RUN set -eu && apt-get install -y \ - ccache \ - clang-8 \ - clang-format-8 \ - clang-tidy-8 \ - cmake \ - fonts-noto \ - g++-8 \ - libc++-8-dev \ - libc++abi-8-dev \ - mesa-common-dev \ - ninja-build \ - nodejs \ - npm \ - pkg-config \ - python3-pip \ - python3-requests \ - python3-github \ - software-properties-common \ - valgrind \ - xvfb \ - && apt-get autoremove --purge -y && apt-get clean - -RUN pip3 install cmake-format==0.5.5 - -# Linux dependencies -RUN set -eu && apt-get install -y \ - libcurl4-openssl-dev \ - libgl1-mesa-dev \ - libgles2-mesa-dev \ - libglfw3-dev \ - libicu-dev \ - libjpeg-turbo8-dev \ - libpng-dev \ - libuv1-dev \ - zlib1g-dev \ - && apt-get autoremove --purge -y && apt-get clean - -# Qt dependencies -RUN set -eu && apt-get install -y \ - qdoc-qt5 \ - qt5-default \ - && apt-get autoremove --purge -y && apt-get clean - -# Android dependencies -RUN set -eu && apt-get install -y \ - coreutils \ - curl \ - openjdk-8-jdk-headless \ - unzip \ - && apt-get autoremove --purge -y && apt-get clean - -# Install old compilers -RUN set -eu \ - && apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1E9377A2BA9EF27F \ - && add-apt-repository "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" \ - && add-apt-repository "deb http://us.archive.ubuntu.com/ubuntu/ xenial main universe" \ - && apt-get install -y g++-5 \ - && apt-get autoremove --purge -y && apt-get clean - -# Install Android NDK -RUN set -eu \ - && mkdir -p ${ANDROID_HOME} && cd ${ANDROID_HOME} \ - && curl -L --retry 3 https://dl.google.com/android/repository/android-ndk-r19-linux-x86_64.zip -o ndk.zip \ - && (echo "f02ad84cb5b6e1ff3eea9e6168037c823408c8ac ndk.zip" | sha1sum -c) \ - && unzip -q ndk.zip && rm ndk.zip && mv android-ndk-r* ndk-bundle - - -RUN set -eu \ - && cd ${ANDROID_HOME} \ - && curl -L --retry 3 https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip -o tools.zip \ - && (echo "92ffee5a1d98d856634e8b71132e8a95d96c83a63fde1099be3d86df3106def9 tools.zip" | sha256sum -c) \ - && unzip -q tools.zip && rm tools.zip - -RUN set -eu \ - && yes | ${ANDROID_HOME}/tools/bin/sdkmanager \ - "platform-tools" \ - "platforms;android-26" \ - "build-tools;26.0.3" \ - "platforms;android-27" \ - "build-tools;27.0.3" \ - "platforms;android-28" \ - "build-tools;28.0.3" \ - "extras;android;m2repository" \ - "patcher;v4" \ - "extras;google;m2repository" \ - "extras;m2repository;com;android;support;constraint;constraint-layout;1.0.2" \ - "cmake;3.10.2.4988404" - -# Install gcloud for Firebase testing -RUN set -eu \ - && echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list \ - && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - \ - && apt-get update -y \ - && apt-get install google-cloud-sdk -y \ - && apt-get autoremove --purge -y && apt-get clean - -# FIXME: This package should not be needed -# bug looks like run-clang-tidy-8 is broken. -# Remove when Ubuntu Eoan fixes the dependency. -RUN set -eu && apt-get install -y \ - python-yaml \ - && apt-get autoremove --purge -y && apt-get clean - -# Configure ccache -RUN set -eu && /usr/sbin/update-ccache-symlinks diff --git a/scripts/ci/etc/apt/sources.list b/scripts/ci/etc/apt/sources.list deleted file mode 100644 index 7ec110761..000000000 --- a/scripts/ci/etc/apt/sources.list +++ /dev/null @@ -1,10 +0,0 @@ -deb http://fi.archive.ubuntu.com/ubuntu/ eoan main restricted -deb http://fi.archive.ubuntu.com/ubuntu/ eoan-updates main restricted -deb http://fi.archive.ubuntu.com/ubuntu/ eoan universe -deb http://fi.archive.ubuntu.com/ubuntu/ eoan-updates universe -deb http://fi.archive.ubuntu.com/ubuntu/ eoan multiverse -deb http://fi.archive.ubuntu.com/ubuntu/ eoan-updates multiverse -deb http://fi.archive.ubuntu.com/ubuntu/ eoan-backports main restricted universe multiverse -deb http://security.ubuntu.com/ubuntu/ eoan-security main restricted -deb http://security.ubuntu.com/ubuntu/ eoan-security universe -deb http://security.ubuntu.com/ubuntu/ eoan-security multiverse diff --git a/scripts/clang-tidy-diff.py b/scripts/clang-tidy-diff.py deleted file mode 100755 index e5e0ff391..000000000 --- a/scripts/clang-tidy-diff.py +++ /dev/null @@ -1,201 +0,0 @@ -#!/usr/bin/env python -# -#===- clang-tidy-diff.py - ClangTidy Diff Checker ------------*- python -*--===# -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -#===------------------------------------------------------------------------===# - -r""" -ClangTidy Diff Checker -====================== - -This script reads input from a unified diff, runs clang-tidy on all changed -files and outputs clang-tidy warnings in changed lines only. This is useful to -detect clang-tidy regressions in the lines touched by a specific patch. -Example usage for git/svn users: - - git diff -U0 HEAD^ | clang-tidy-diff.py -p1 - svn diff --diff-cmd=diff -x-U0 | \ - clang-tidy-diff.py -fix -checks=-*,modernize-use-override - -""" - -import argparse -import json -import re -import subprocess -import sys -import multiprocessing -import os -import threading - -is_py2 = sys.version[0] == '2' - -if is_py2: - import Queue as queue -else: - import queue as queue - -def run_tidy(command, lines_by_file, queue, failed_files): - """Takes filenames out of queue and runs clang-tidy on them.""" - while True: - name = queue.get() - - line_filter_json = json.dumps([{"name" : name, "lines" : lines_by_file[name]}], separators = (',', ':')) - if sys.platform == 'win32': - line_filter_json = re.sub(r'"', r'"""', line_filter_json) - else: - line_filter_json = "'" + line_filter_json + "'"; - - invocation = list(command) - invocation.append('-line-filter=' + line_filter_json) - invocation.append(name) - - sys.stdout.write('Checking differences in {}...\n'.format(name)) - return_code = subprocess.call(' '.join(invocation), shell=True) - if return_code != 0: - failed_files.append(name) - queue.task_done() - -def main(): - parser = argparse.ArgumentParser(description= - 'Run clang-tidy against changed files, and ' - 'output diagnostics only for modified ' - 'lines.') - parser.add_argument('-clang-tidy-binary', metavar='PATH', - default='clang-tidy', - help='path to clang-tidy binary') - parser.add_argument('-p', metavar='NUM', default=0, - help='strip the smallest prefix containing P slashes') - parser.add_argument('-regex', metavar='PATTERN', default=None, - help='custom pattern selecting file paths to check ' - '(case sensitive, overrides -iregex)') - parser.add_argument('-iregex', metavar='PATTERN', default= - r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc)', - help='custom pattern selecting file paths to check ' - '(case insensitive, overridden by -regex)') - - parser.add_argument('-fix', action='store_true', default=False, - help='apply suggested fixes') - parser.add_argument('-checks', - help='checks filter, when not specified, use clang-tidy ' - 'default', - default='') - parser.add_argument('-path', dest='build_path', - help='Path used to read a compile command database.') - parser.add_argument('-extra-arg', dest='extra_arg', - action='append', default=[], - help='Additional argument to append to the compiler ' - 'command line.') - parser.add_argument('-extra-arg-before', dest='extra_arg_before', - action='append', default=[], - help='Additional argument to prepend to the compiler ' - 'command line.') - parser.add_argument('-j', type=int, default=0, - help='number of tidy instances to be run in parallel.') - parser.add_argument('-quiet', action='store_true', default=False, - help='Run clang-tidy in quiet mode') - clang_tidy_args = [] - argv = sys.argv[1:] - if '--' in argv: - clang_tidy_args.extend(argv[argv.index('--'):]) - argv = argv[:argv.index('--')] - - args = parser.parse_args(argv) - - # Extract changed lines for each file. - filename = None - lines_by_file = {} - for line in sys.stdin: - match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line) - if match: - filename = match.group(2) - if filename == None: - continue - - if args.regex is not None: - if not re.match('^%s$' % args.regex, filename): - continue - else: - if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE): - continue - - match = re.search('^@@.*\+(\d+)(,(\d+))?', line) - if match: - start_line = int(match.group(1)) - line_count = 1 - if match.group(3): - line_count = int(match.group(3)) - if line_count == 0: - continue - end_line = start_line + line_count - 1; - lines_by_file.setdefault(filename, []).append([start_line, end_line]) - - if len(lines_by_file) == 0: - print("No relevant changes found.") - sys.exit(0) - - # Run clang-tidy on files containing changes. - command = [args.clang_tidy_binary] - if args.fix: - command.append('-fix') - if args.checks != '': - command.append('-checks=' + quote + args.checks + quote) - if args.quiet: - command.append('-quiet') - if args.build_path is not None: - command.append('-p=%s' % args.build_path) - for arg in args.extra_arg: - command.append('-extra-arg=%s' % arg) - for arg in args.extra_arg_before: - command.append('-extra-arg-before=%s' % arg) - command.extend(clang_tidy_args) - - try: - invocation = list(command) - invocation.append('-') - subprocess.check_call(invocation) - except: - print("Unable to run clang-tidy: {}".format(' '.join(command))) - sys.exit(1) - - max_task = args.j - if max_task == 0: - max_task = multiprocessing.cpu_count() - - return_code = 0 - try: - # Spin up a bunch of tidy-launching threads. - task_queue = queue.Queue(max_task) - # List of files with a non-zero return code. - failed_files = [] - for _ in range(max_task): - t = threading.Thread(target=run_tidy, - args=(command, lines_by_file, task_queue, failed_files)) - t.daemon = True - t.start() - - # Fill the queue with files. - for name in lines_by_file: - task_queue.put(name) - - # Wait for all threads to be done. - task_queue.join() - if len(failed_files): - return_code = 1 - - except KeyboardInterrupt: - # This is a sad hack. Unfortunately subprocess goes - # bonkers with ctrl-c and we start forking merrily. - print('\nCtrl-C detected, goodbye.') - os.kill(0, 9) - return_code = 1 - - sys.exit(return_code) - -if __name__ == '__main__': - main() diff --git a/scripts/clang-tools.sh b/scripts/clang-tools.sh deleted file mode 100755 index 54a395848..000000000 --- a/scripts/clang-tools.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -CLANG_TIDY_PREFIX=${CLANG_TIDY_PREFIX:-$(scripts/mason.sh PREFIX clang-tidy VERSION 7.0.0)} -CLANG_TIDY=${CLANG_TIDY_PREFIX}/bin/clang-tidy -CLANG_APPLY=${CLANG_TIDY_PREFIX}/bin/clang-apply-replacements - -for CLANG_FILE in "${CLANG_TIDY}" "${CLANG_APPLY}"; do - command -v "${CLANG_FILE}" > /dev/null 2>&1 || { - echo "Can't find ${CLANG_FILE} in PATH." - if [ -z "${CLANG_FILE}" ]; then - echo "Alternatively, you can manually set ${!CLANG_FILE@}." - fi - exit 1 - } -done - -echo "Running Clang checks... (this might take a while)" - -if [[ -n ${3:-} ]] && [[ ${3:-} == "--diff" ]]; then - git diff "origin/$2" | "scripts/clang-tidy-diff.py" \ - -clang-tidy-binary "${CLANG_TIDY}" \ - -p 1 -quiet -path "$1" -else - git ls-files "src/*.cpp" "test/*.cpp" "platform/*.cpp" "bin/*.cpp" | \ - xargs "${CLANG_TIDY_PREFIX}/share/run-clang-tidy.py" \ - -clang-tidy-binary "${CLANG_TIDY}" \ - -clang-apply-replacements-binary "${CLANG_APPLY}" \ - -quiet -p "$1" -fix -fi diff --git a/scripts/code-coverage.sh b/scripts/code-coverage.sh deleted file mode 100755 index cb99bd964..000000000 --- a/scripts/code-coverage.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -o pipefail - -# -# This script takes three values: $1 should be a decimal value reflecting the -# percentage of lines covered, with a maximum value of 100.0, $2 is -# the platform the percentage pertains to (iOS or Android), and $3 is the -# test scheme being run (on iOS, this is currently CI). -# - -# Check that platform input values are valid. - -if [[ ! $2 = "iOS" && ! $2 = "Android" ]]; then - echo "$2 does not match either 'iOS' or 'Android'. Platform must be specified for coverage report." - exit 1 -fi - -circle_sha="" -if [[ $CIRCLE_SHA1 ]]; then - circle_sha="$CIRCLE_SHA1" -fi -# Create a formatted JSON file that contains the current coverage. - -current_date=$(TZ=UTC date +"%FT%T%z") -file_name=$2_coverage.json -cat < $file_name -{"code_coverage":$1,"platform":"$2","sdk":"Maps","scheme":"$3","created_at":"$current_date","sha":"$circle_sha"} -EOF -gzip -f $file_name - -if [ -z `which aws` ]; then - brew install awscli -fi - -aws s3 cp $file_name.gz s3://mapbox-loading-dock/raw/mobile.codecoverage/$current_date/ -echo $ diff --git a/scripts/doxy-coverage.py b/scripts/doxy-coverage.py deleted file mode 100755 index b721d57a7..000000000 --- a/scripts/doxy-coverage.py +++ /dev/null @@ -1,211 +0,0 @@ -#!/usr/bin/env python -# -*- mode: python; coding: utf-8 -*- - -# All files in doxy-coverage are Copyright 2014 Alvaro Lopez Ortega. -# -# Authors: -# * Alvaro Lopez Ortega -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -from __future__ import print_function - -__author__ = "Alvaro Lopez Ortega" -__email__ = "alvaro@alobbs.com" -__copyright__ = "Copyright (C) 2014 Alvaro Lopez Ortega" - -import os -import sys -import argparse -import xml.etree.ElementTree as ET - -# Defaults -ACCEPTABLE_COVERAGE = 80 - -# Global -ns = None - -def ERROR(*objs): - print("ERROR: ", *objs, end='\n', file=sys.stderr) - -def FATAL(*objs): - ERROR (*objs) - sys.exit((1,0)[ns.noerror]) - -def parse_file(fullpath): - tree = ET.parse(fullpath) - - sourcefile = None - definitions = {} - - for definition in tree.findall("./compounddef//memberdef"): - # Should it be documented - if definition.get('prot') == 'private' or ( - definition.get('kind') == 'function' and - definition.get('static') == 'yes'): - continue - - # Is the definition documented? - documented = False - for k in ('briefdescription', 'detaileddescription', 'inbodydescription'): - if definition.findall("./%s/"%(k)): - documented = True - break - - # Name - d_def = definition.find('./definition') - d_nam = definition.find('./name') - - if not sourcefile: - l = definition.find('./location') - if l is not None: - sourcefile = l.get('file') - - if d_def is not None: - name = d_def.text - elif d_nam is not None: - name = d_nam.text - else: - name = definition.get('id') - - # Aggregate - definitions[name] = documented - - if not sourcefile: - sourcefile = fullpath - - return (sourcefile, definitions) - - -def parse(path): - index_fp = os.path.join (path, "index.xml") - if not os.path.exists (index_fp): - FATAL ("Documentation not present. Exiting.", index_fp) - - tree = ET.parse(index_fp) - - files = {} - for entry in tree.findall('compound'): - if entry.get('kind') in ('dir'): - continue - - file_fp = os.path.join (path, "%s.xml" %(entry.get('refid'))) - tmp = parse_file (file_fp) - files[tmp[0]] = tmp[1] - - return files - - -def report (files, exclude_dirs): - def get_coverage (f): - defs = files[f] - if not defs: - return 100 - - doc_yes = len([d for d in defs.values() if d]) - doc_no = len([d for d in defs.values() if not d]) - return (doc_yes * 100.0 / (doc_yes + doc_no)) - - def file_cmp (a,b): - return cmp(get_coverage(a), get_coverage(b)) - - files_sorted = files.keys() - files_sorted.sort(file_cmp) - files_sorted.reverse() - - total_yes = 0 - total_no = 0 - - for f in files_sorted: - skip = False - for exclude_dir in exclude_dirs: - if exclude_dir in f: - skip = True - break - if skip: - continue - - defs = files[f] - if not defs: - continue - - doc_yes = len([d for d in defs.values() if d]) - doc_no = len([d for d in defs.values() if not d]) - doc_per = doc_yes * 100.0 / (doc_yes + doc_no) - - total_yes += doc_yes - total_no += doc_no - - if not ns.quiet: - print ('%3d%% - %s - (%d of %d)'%(doc_per, f, doc_yes, (doc_yes + doc_no))) - - defs_sorted = defs.keys() - defs_sorted.sort() - for d in defs_sorted: - if not defs[d]: - print ("\t", d) - - total_all = total_yes + total_no - total_per = total_yes * 100 / total_all - if not ns.quiet: - print() - print("%d%% API documentation coverage (%d out of %d)" %(total_per, total_yes, total_all)) - - if ns.json: - with open(ns.json, "w") as f: - f.write('{"documented": %d, "total": %d}\n' % (total_yes, total_all)) - - return (ns.threshold - total_per, 0)[total_per > ns.threshold] - - -def main(): - # Arguments - parser = argparse.ArgumentParser() - parser.add_argument ("dir", action="store", help="Path to Doxygen's XML doc directory") - parser.add_argument ("--noerror", action="store_true", help="Do not return error code after execution") - parser.add_argument ("--threshold", action="store", help="Min acceptable coverage percentage (Default: %s)"%(ACCEPTABLE_COVERAGE), default=ACCEPTABLE_COVERAGE, type=int) - parser.add_argument ("--quiet", action="store_true", help="Don't output report to standard output") - parser.add_argument ("--json", action="store", help="Output json coverage report to specified json file") - parser.add_argument("--excludedirs", nargs='+', help="List of directories to be excluded from coverage analysis", type=str, default=[]) - - - global ns - ns = parser.parse_args() - if not ns: - FATAL ("ERROR: Couldn't parse parameters") - - # Parse - files = parse (ns.dir) - - # Print report - err = report (files, ns.excludedirs) - if ns.noerror: - return - - sys.exit(err) - - -if __name__ == "__main__": - main() diff --git a/scripts/notify-slack.sh b/scripts/notify-slack.sh deleted file mode 100755 index 5b637e87a..000000000 --- a/scripts/notify-slack.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -o pipefail -set -u - -SLACK_CHANNEL=${SLACK_CHANNEL:-''} -SLACK_COLOR=${SLACK_COLOR:-''} - -curl -g -H "Content-Type: application/json" -X POST \ - -d "{\"channel\": \"$SLACK_CHANNEL\", \"attachments\": [{\"text\": \"$SLACK_MESSAGE\", \"color\": \"$SLACK_COLOR\", \"author_name\": \"$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME\"}]}" \ - $SLACK_WEBHOOK_URL diff --git a/scripts/publish_binary_size.js b/scripts/publish_binary_size.js deleted file mode 100755 index e40c9cb9e..000000000 --- a/scripts/publish_binary_size.js +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/env node - -const jwt = require('jsonwebtoken'); -const github = require('@octokit/rest').plugin(require('@octokit/plugin-retry'))({ - retry: { doNotRetry: [ /* Empty — retry on any error code. */ ] } -}) -const zlib = require('zlib'); -const AWS = require('aws-sdk'); - -const SIZE_CHECK_APP_ID = 14028; -const SIZE_CHECK_APP_INSTALLATION_ID = 229425; - -process.on('unhandledRejection', error => { - console.log(error); - process.exit(1) -}); - -const pk = process.env['SIZE_CHECK_APP_PRIVATE_KEY']; -if (!pk) { - console.log('Fork PR; not publishing size.'); - process.exit(0); -} - -const key = Buffer.from(pk, 'base64').toString('binary'); -const payload = { - exp: Math.floor(Date.now() / 1000) + 60, - iat: Math.floor(Date.now() / 1000), - iss: SIZE_CHECK_APP_ID -}; - -const token = jwt.sign(payload, key, {algorithm: 'RS256'}); -github.authenticate({type: 'app', token}); - -// Must be in sync with the definition in metrics/binary-size/index.html on the gh-pages branch. -const platforms = [ - { 'platform': 'iOS', 'arch': 'armv7' }, - { 'platform': 'iOS', 'arch': 'arm64' }, - { 'platform': 'iOS', 'arch': 'Dynamic' }, - { 'platform': 'Android', 'arch': 'arm-v7' }, - { 'platform': 'Android', 'arch': 'arm-v8' }, - { 'platform': 'Android', 'arch': 'x86' }, - { 'platform': 'Android', 'arch': 'x86_64' } -]; - -const sizeCheckInfo = []; -const rows = []; -const date = new Date().toISOString().substring(0, 19); - -function query(after) { - return github.request({ - method: 'POST', - url: '/graphql', - headers: { - // https://developer.github.com/changes/2018-07-11-graphql-checks-preview/ - accept: 'application/vnd.github.antiope-preview' - }, - query: `query { - repository(owner: "mapbox", name: "mapbox-gl-native") { - ref(qualifiedName: "main") { - target { - ... on Commit { - history(first: 100, before: "36c6a8ea79bbd2596abb58ffb58debf65a4ea13d" ${after ? `, after: "${after}"` : ''}) { - pageInfo { - hasNextPage - endCursor - } - edges { - node { - oid - messageHeadline - checkSuites(first: 1, filterBy: {appId: ${SIZE_CHECK_APP_ID}}) { - nodes { - checkRuns(first: 10) { - nodes { - name - conclusion - title - summary - } - } - } - } - } - } - } - } - } - } - } - }` - }).then((result) => { - - const history = result.data.data.repository.ref.target.history; - - for (const edge of history.edges) { - const commit = edge.node; - const suite = commit.checkSuites.nodes[0]; - - if (!suite) - continue; - const allRuns = commit.checkSuites.nodes[0].checkRuns.nodes; - - const sizeCheckRuns = allRuns.filter(function (run) { - return run.name.match(/Size - (\w+) ([\w-]+)/); - }); - - const row = [`${commit.oid.slice(0, 7)} - ${commit.messageHeadline}`]; - - for (let i = 0; i < platforms.length; i++) { - const {platform, arch} = platforms[i]; - - const run = sizeCheckRuns.find((run) => { - const [, p, a] = run.name.match(/Size - (\w+) ([\w-]+)/); - return platform === p && arch === a; - }); - - row[i + 1] = run ? +run.summary.match(/is (\d+) bytes/)[1] : undefined; - } - rows.push(row); - } - - if (history.pageInfo.hasNextPage) { - return query(history.pageInfo.endCursor); - } else { - const latestRun = rows[0] - const runSizeMeasurements = latestRun.slice(1) - - for (let i = 0; i < platforms.length; i++) { - const {platform, arch} = platforms[i]; - - sizeCheckInfo.push(JSON.stringify({ - 'sdk': 'maps', - 'platform' : platform, - 'arch': arch, - 'size' : runSizeMeasurements[i], - 'created_at': date - })); - } - } - }); -} - -github.apps.createInstallationToken({installation_id: SIZE_CHECK_APP_INSTALLATION_ID}) - .then(({data}) => { - github.authenticate({type: 'token', token: data.token}); - - return query().then(function() { - // Uploads to data source used by - // http://mapbox.github.io/mapbox-gl-native/metrics/binary-size/ - var firstPromise = new AWS.S3({region: 'us-east-1'}).putObject({ - Body: zlib.gzipSync(JSON.stringify(rows.reverse())), - Bucket: 'mapbox', - Key: 'mapbox-gl-native/metrics/binary-size/data.json', - ACL: 'public-read', - CacheControl: 'max-age=300', - ContentEncoding: 'gzip', - ContentType: 'application/json' - }).promise(); - // Uploads to data source used by Mapbox internal metrics dashboards - var secondPromise = new AWS.S3({region: 'us-east-1'}).putObject({ - Body: zlib.gzipSync(sizeCheckInfo.join('\n')), - Bucket: 'mapbox-loading-dock', - Key: `raw/mobile.binarysize/${date.substring(0,10)}/mapbox-maps-ios-android-${process.env['CIRCLE_SHA1']}.json.gz`, - CacheControl: 'max-age=300', - ContentEncoding: 'gzip', - ContentType: 'application/json' - }).promise(); - - return Promise.all([firstPromise, secondPromise]).then(data => { - return console.log("Successfully uploaded all binary size metrics to S3"); - }).catch(err => { - console.log("Error uploading binary size metrics to S3 " + err.message); - return err; - }); - }); -}); - - \ No newline at end of file diff --git a/scripts/publish_core_codecoverage.js b/scripts/publish_core_codecoverage.js deleted file mode 100755 index 43de662a1..000000000 --- a/scripts/publish_core_codecoverage.js +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env node - -// Script to retrieve total code coverage ratio from codecov.io -// for a given commit hash, and upload it to the S3 bucket. - -const https = require('https'); -const zlib = require('zlib'); -const AWS = require('aws-sdk'); -const {execSync} = require('child_process'); - -const args = process.argv.slice(2); -const options = { - help: false -}; - -const usage = 'usage: publish_code_coverage.js [options]\n' + -'options: \n' + -' -h, --help \n' + -' -p, --platform \n' + -' -s, --sdk \n' + -' -c, --commit \n'; - -for (var i = 0; i < args.length; i++) { - var arg = args[i]; - - switch(arg) { - case '-h': - case '--help': - options.help = true; - break; - case '-s': - case '--sdk': - options.sdkName = args[i + 1]; - break; - case '-p': - case '--platform': - options.platformName = args[i + 1]; - break; - case '-c': - case '--commit': - options.commitId = args[i + 1]; - break; - } -} - -if (options.help == true) { - console.log(usage); - process.exit(0); -} - -// Commit hash -const commitHash = options.commitId ? options.commitId : process.env['CIRCLE_SHA1']; -if (!options.sdkName || !options.platformName || !commitHash) { - console.log(usage); - process.exit(0); -} - -// Commit Message -const commitMessage = execSync(`git show --pretty=format:%s -s ${commitHash}`).toString().trim(); -if (!commitMessage) { - throw new Error ('Commit message is missing'); -} - -const date = new Date().toISOString().substring(0, 19); - -process.on('uncaughtException', (err) => { - console.error(err); - process.exit(1); -}); - -// Parse the response received from codecov.io and build the -// data point that is going to be uploaded to S3 bucket. -function parseResponse(data) { - if (data && data.commit) { - if (!data.commit.totals || !data.commit.totals.c) { - return; - } - - const source = { - code_coverage: Number(data.commit.totals.c), - platform: options.platformName, - sdk: options.sdkName, - commit: commitHash, - commit_message: commitMessage, - created_at: date - }; - - return source; - } -} - -// Upload to data source used by Mapbox internal metrics dashboards -function uploadData(data) { - return new AWS.S3({region: 'us-east-1'}).putObject({ - Body: zlib.gzipSync(JSON.stringify(data)), - Bucket: 'mapbox-loading-dock', - Key: `raw/mobile_staging.codecoverage/${date.substring(0,10)}/${options.sdkName}-coverage-${commitHash}.json.gz`, - CacheControl: 'max-age=300', - ContentEncoding: 'gzip', - ContentType: 'application/json' - }).promise(); -} - -// Attempt to retrieve code coverage report from codecov.io -// for a given commit hash. -function httpRequest() { - const options = { - hostname: 'codecov.io', - port: 443, - path: '/api/gh/mapbox/mapbox-gl-native/commit/' + commitHash, - method: 'GET' - }; - - return new Promise((resolve, reject) => { - setTimeout(function() { - const req = https.request(options, (res) => { - var body = []; - res.on('data', (chunk) => { - body.push(chunk); - }).on('error', (error) => { - reject(error); - }).on('end', () => { - if (res.statusCode < 200 || res.statusCode >= 300) { - return reject(new Error('Failed to fetch coverage report from codecov.io. StatusCode=' + res.statusCode)); - } - - try { - body = JSON.parse(Buffer.concat(body).toString()); - resolve(body); - } catch(e) { - reject(e); - } - }); - }); - - // Reject on error - req.on('error', (err) => { - reject(err); - }); - - req.end(); - }, 30000); - }); -} - -var errResponse = false; -const publishWithRetry = (maxRetries) => { - httpRequest().then((body) => { - const dataSource = parseResponse(body); - if (dataSource) { - return uploadData(dataSource); - } else { - errResponse = true; - throw new Error('Failed to parse coverage report received from codecov.io.'); - } - }).then(data => { - console.log('Successfully uploaded code coverage metrics to S3'); - }).catch(err => { - if (maxRetries > 1 && errResponse) { - console.log('Invalid coverage report received. Trying to retrieve again.'); - errResponse = false; - return publishWithRetry(maxRetries - 1); - } - - console.error('Failed to upload code coverage metrics to S3: ' + err.message); - }); -}; - -// Fetch and publish code coverage report -publishWithRetry(5); diff --git a/scripts/publish_doxygen_coverage.js b/scripts/publish_doxygen_coverage.js deleted file mode 100755 index f41cf5bb2..000000000 --- a/scripts/publish_doxygen_coverage.js +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env node - -const jwt = require('jsonwebtoken'); -const github = require('@octokit/rest').plugin(require('@octokit/plugin-retry'))({ - retry: { doNotRetry: [ /* Empty — retry on any error code. */ ] } -}) -const zlib = require('zlib'); -const AWS = require('aws-sdk'); -const fs = require('fs'); - -const SIZE_CHECK_APP_ID = 14028; -const SIZE_CHECK_APP_INSTALLATION_ID = 229425; - -var coverage; - -try { - coverage = JSON.parse(fs.readFileSync(process.argv[2])); - if (typeof coverage.documented !== 'number' || typeof coverage.total !== 'number' || - coverage.documented > coverage.total) { - throw new Error('Invalid coverage.json file'); - } -} catch (error) { - console.log('Failed to parse json file with coverage data: ', error); - process.exit(1); -} - -process.on('unhandledRejection', error => { - console.log(error); - process.exit(1); -}); - -const pk = process.env['SIZE_CHECK_APP_PRIVATE_KEY']; -if (!pk) { - console.log('Fork PR; not publishing size.'); - process.exit(0); -} - -const key = Buffer.from(pk, 'base64').toString('binary'); -const payload = { - exp: Math.floor(Date.now() / 1000) + 60, - iat: Math.floor(Date.now() / 1000), - iss: SIZE_CHECK_APP_ID -}; - -const token = jwt.sign(payload, key, {algorithm: 'RS256'}); -github.authenticate({type: 'app', token}); - -github.apps.createInstallationToken({installation_id: SIZE_CHECK_APP_INSTALLATION_ID}) - .then(({data}) => { - github.authenticate({type: 'token', token: data.token}); - const percentage = coverage.documented * 100 / coverage.total; - const title = `${percentage.toFixed(2)}%`; - const date = new Date().toISOString().substring(0, 19); - - var promises = [github.checks.create({ - owner: 'mapbox', - repo: 'mapbox-gl-native', - name: 'Doxygen coverage', - head_branch: process.env['CIRCLE_BRANCH'], - head_sha: process.env['CIRCLE_SHA1'], - status: 'completed', - conclusion: 'success', - completed_at: new Date().toISOString(), - output: { - title, - summary: `There is doxygen documentation for ${percentage}% of the public symbols (${coverage.documented} out of ${coverage.total})` - } - })]; - - if (process.env['CIRCLE_BRANCH'] === 'main') { - promises.push(new AWS.S3({region: 'us-east-1'}).putObject({ - Body: zlib.gzipSync(JSON.stringify({ - 'created_at': date, - 'documented': coverage.documented, - 'total': coverage.total, - 'commit': process.env['CIRCLE_SHA1'] - })), - Bucket: 'mapbox-loading-dock', - Key: `raw/mobile_staging.docs_coverage/${date.substring(0,10)}/${process.env['CIRCLE_SHA1']}.json.gz`, - CacheControl: 'max-age=300', - ContentEncoding: 'gzip', - ContentType: 'application/json' - }).promise()); - } - - return Promise.all(promises).then(data => { - return console.log('Succesfully uploaded doxygen coverage metrics'); - }).catch(err => { - console.log('Error uploading doxygen coverage metrics: ' + err.message); - return err; - }); - });