From 4d56baded82c7e041612a1a398c08c84941581d6 Mon Sep 17 00:00:00 2001 From: Thierry Carrez Date: Tue, 3 Jul 2018 15:40:01 +0200 Subject: [PATCH] Remove team diversity tags Team diversity tags (single-vendor and diverse-affiliation) no longer provide useful context for our users: - As projects mature and feature development activity is more limited, a lot of projects were flapping between states depending on a couple commits or reviews, cross-project work or community goals activity. - In teams where a single individual ends up picking up the bulk of core reviewing duties, the diversity tags incentivized them to limit their activity. - Data was based on Stackalytics, which is not a highly reliable data source. Basing tags on raw data is not a great idea. Raw diversity data should be used to raise flags for further analysis (with context) rather than jumping to conclusions. - Binary tags can't reflect the complexity of that data. Single-vendor does not mean the same for PowerVMStackers and for Keystone. Trends are actually more important than value at a single point in time. - Organizational diversity is just one factor of fragility for project teams. Individual fragility (where the bulk of the work is done by one person) is actually more prevalent those days. Change-Id: I1f1e55a7605ddff572b7b674c58ab419a7fc913f --- reference/legacy.yaml | 10 - reference/projects.yaml | 77 ------ reference/tags/index.rst | 2 - reference/tags/team_diverse-affiliation.rst | 77 ------ reference/tags/team_single-vendor.rst | 78 ------ tools/teamstats.py | 280 -------------------- tools/validate_tags.py | 100 ------- 7 files changed, 624 deletions(-) delete mode 100644 reference/tags/team_diverse-affiliation.rst delete mode 100644 reference/tags/team_single-vendor.rst delete mode 100644 tools/teamstats.py delete mode 100755 tools/validate_tags.py diff --git a/reference/legacy.yaml b/reference/legacy.yaml index 4da0d9944..3e21dabda 100644 --- a/reference/legacy.yaml +++ b/reference/legacy.yaml @@ -16,8 +16,6 @@ astara: load balancing, vpn) for connecting and security multi-tenant OpenStack environments. url: https://wiki.openstack.org/wiki/Astara - tags: - - team:single-vendor deliverables: astara: repos: @@ -55,8 +53,6 @@ Chef OpenStack: and consumption of OpenStack cloud deployments. url: https://wiki.openstack.org/wiki/Chef partial: yes - tags: - - team:diverse-affiliation deliverables: cookbook-openstack-bare-metal: repos: @@ -112,8 +108,6 @@ cue: To provide a multi-tenant service that offers scalable and reliable provisioning and management capabilities for off-the-shelf message brokers. url: https://wiki.openstack.org/wiki/Cue - tags: - - team:single-vendor deliverables: cue: repos: @@ -359,8 +353,6 @@ OpenStackSalt: based IT automation for installing and operating OpenStack deployments. url: https://wiki.openstack.org/wiki/OpenStackSalt - tags: - - team:single-vendor deliverables: openstack-salt: repos: @@ -474,8 +466,6 @@ Packaging-deb: mission: > Maintain packages for Debian (and other deb based distributions) as a community. - tags: - - team:single-vendor deliverables: deb-alembic: repos: diff --git a/reference/projects.yaml b/reference/projects.yaml index 301e49779..edb7335ea 100644 --- a/reference/projects.yaml +++ b/reference/projects.yaml @@ -10,8 +10,6 @@ barbican: To produce a secret storage and generation system capable of providing key management for services wishing to enable encryption features. url: https://wiki.openstack.org/wiki/Barbican - tags: - - team:diverse-affiliation deliverables: barbican: repos: @@ -146,8 +144,6 @@ cinder: access to Block Storage resources via abstraction and automation on top of other block storage devices. url: https://wiki.openstack.org/wiki/Cinder - tags: - - team:diverse-affiliation deliverables: cinder: repos: @@ -283,8 +279,6 @@ designate: To provide scalable, on demand, self service access to authoritative DNS services, in technology-agnostic manner. url: https://wiki.openstack.org/wiki/Designate - tags: - - team:diverse-affiliation deliverables: designate: repos: @@ -323,8 +317,6 @@ Documentation: guides enabling OpenStack project teams to produce consistent, accurate, and high-quality documentation. url: https://wiki.openstack.org/wiki/Documentation - tags: - - team:diverse-affiliation deliverables: constellations: repos: @@ -373,8 +365,6 @@ dragonflow: It's designed to support containers networking and large scale production loads. url: https://wiki.openstack.org/wiki/Dragonflow - tags: - - team:single-vendor deliverables: dragonflow: repos: @@ -535,8 +525,6 @@ horizon: To provide an extensible unified web based user interface for all OpenStack services. url: https://wiki.openstack.org/wiki/Horizon - tags: - - team:diverse-affiliation deliverables: django_openstack_auth: repos: @@ -662,8 +650,6 @@ I18n: To make OpenStack ubiquitously accessible to people of all language backgrounds. url: https://wiki.openstack.org/wiki/I18nTeam - tags: - - team:diverse-affiliation deliverables: i18n: repos: @@ -1023,8 +1009,6 @@ Infrastructure: Develop and maintain the tooling and infrastructure needed to support the development process and general operation of the OpenStack project. url: https://docs.openstack.org/infra/system-config/ - tags: - - team:diverse-affiliation deliverables: activity-board: repos: @@ -1513,8 +1497,6 @@ ironic: managing and provisioning physical machines, and to do this in a security-aware and fault-tolerant manner. url: https://wiki.openstack.org/wiki/Ironic - tags: - - team:diverse-affiliation deliverables: bifrost: repos: @@ -1633,8 +1615,6 @@ keystone: To facilitate API client authentication, service discovery, distributed multi-tenant authorization, and auditing. url: https://wiki.openstack.org/wiki/Keystone - tags: - - team:diverse-affiliation deliverables: keystone: repos: @@ -1689,8 +1669,6 @@ kolla: To provide production-ready containers and deployment tools for operating OpenStack clouds. url: https://wiki.openstack.org/wiki/Kolla - tags: - - team:diverse-affiliation deliverables: kolla: repos: @@ -1761,8 +1739,6 @@ magnum: To provide a set of services for provisioning, scaling, and managing container orchestration engines. url: https://wiki.openstack.org/wiki/Magnum - tags: - - team:diverse-affiliation deliverables: magnum: repos: @@ -1792,8 +1768,6 @@ manila: in a multitenant cloud environment, similar to how OpenStack provides for block-based storage management through the Cinder project. url: https://wiki.openstack.org/wiki/Manila - tags: - - team:diverse-affiliation deliverables: manila: repos: @@ -1836,8 +1810,6 @@ masakari: Provide instances high availability service for OpenStack clouds by automatically recovering the instances from failures. url: https://wiki.openstack.org/wiki/Masakari - tags: - - team:single-vendor deliverables: masakari: repos: @@ -1903,8 +1875,6 @@ monasca: services that can be used by both operators and tenants to gain operational insight and visibility, ensuring availability and stability. url: https://wiki.openstack.org/wiki/Monasca - tags: - - team:diverse-affiliation deliverables: monasca-api: repos: @@ -2024,8 +1994,6 @@ neutron: To implement services and associated libraries to provide on-demand, scalable, and technology-agnostic network abstraction. url: https://wiki.openstack.org/wiki/Neutron - tags: - - team:diverse-affiliation deliverables: networking-bagpipe: repos: @@ -2113,8 +2081,6 @@ nova: scalable, on demand, self service access to compute resources, including bare metal, virtual machines, and containers. url: https://wiki.openstack.org/wiki/Nova - tags: - - team:diverse-affiliation deliverables: nova: repos: @@ -2201,8 +2167,6 @@ OpenStack Charms: Develop and maintain Juju Charms for deploying and managing OpenStack services. url: https://docs.openstack.org/charm-guide/latest/ - tags: - - team:single-vendor deliverables: charms.ceph: repos: @@ -2456,8 +2420,6 @@ OpenStack-Helm: To provide a collection of Helm charts that simply, resiliently, and flexibly deploy OpenStack and related services on Kubernetes. url: https://wiki.openstack.org/wiki/Openstack-helm - tags: - - team:single-vendor deliverables: openstack-helm: repos: @@ -2610,8 +2572,6 @@ OpenStackClient: Provide a single command-line interface for OpenStack services with a uniform command set and format. url: https://wiki.openstack.org/wiki/OpenStackClient - tags: - - team:diverse-affiliation deliverables: cliff: repos: @@ -2638,8 +2598,6 @@ OpenStackSDK: exposing both the full set of low-level APIs as well as curated higher level business logic. url: https://docs.openstack.org/openstacksdk/latest/ - tags: - - team:diverse-affiliation deliverables: openstacksdk: repos: @@ -2677,8 +2635,6 @@ oslo: projects. The APIs provided by these libraries should be high quality, stable, consistent, documented and generally applicable. url: https://wiki.openstack.org/wiki/Oslo - tags: - - team:diverse-affiliation deliverables: automaton: repos: @@ -2897,8 +2853,6 @@ PowerVMStackers: To provide OpenStack support for the POWER CPU architecture on the PowerVM hypervisor. url: https://wiki.openstack.org/wiki/PowerVM - tags: - - team:single-vendor deliverables: ceilometer-powervm: repos: @@ -3080,8 +3034,6 @@ qinling: Provide a serverless platform for managing functions that can be executed in a scalable, highly-available manner. url: https://wiki.openstack.org/wiki/Qinling - tags: - - team:single-vendor deliverables: qinling: repos: @@ -3101,8 +3053,6 @@ Quality Assurance: stability and quality of OpenStack, and its release readiness at any point during the release cycle. url: https://wiki.openstack.org/wiki/QA - tags: - - team:diverse-affiliation deliverables: bashate: repos: @@ -3228,8 +3178,6 @@ Release Management: versioning rules and tools, then enabling project teams to produce their own releases. url: https://wiki.openstack.org/wiki/Release_Management - tags: - - team:diverse-affiliation deliverables: release-schedule-generator: repos: @@ -3261,8 +3209,6 @@ requirements: while ensuring that all libraries are compatible both technically and from a licensing standpoint. url: https://wiki.openstack.org/wiki/Requirements - tags: - - team:diverse-affiliation deliverables: requirements: repos: @@ -3331,7 +3277,6 @@ searchlight: cloud resources. url: https://wiki.openstack.org/wiki/Searchlight tags: - - team:diverse-affiliation - status:maintenance-mode deliverables: searchlight: @@ -3359,8 +3304,6 @@ Security: for reported vulnerabilities and to foster new security initiatives to the benefit of the OpenStack community as a whole. url: https://wiki.openstack.org/wiki/Security - tags: - - team:diverse-affiliation deliverables: anchor: repos: @@ -3398,8 +3341,6 @@ senlin: To implement clustering services and libraries for the management of groups of homogeneous objects exposed by other OpenStack services. url: https://wiki.openstack.org/wiki/Senlin - tags: - - team:diverse-affiliation deliverables: senlin: repos: @@ -3426,8 +3367,6 @@ solum: application development process by automating the source-to-image process, and simplifying app-centric deployment. url: https://wiki.openstack.org/wiki/Solum - tags: - - team:single-vendor deliverables: python-solumclient: repos: @@ -3456,8 +3395,6 @@ Stable branch maintenance: of a common stable branch policy. Keeping CI working on stable branches. Creating and improving related tooling and automation. url: https://wiki.openstack.org/wiki/StableBranch - tags: - - team:diverse-affiliation deliverables: {} storlets: @@ -3472,8 +3409,6 @@ storlets: executing storage centric user defined functions near the data within OpenStack Swift url: https://wiki.openstack.org/wiki/Storlets - tags: - - team:single-vendor deliverables: storlets: repos: @@ -3595,8 +3530,6 @@ tricircle: To provide networking automation across Neutron in multi-region OpenStack clouds deployment. url: https://wiki.openstack.org/wiki/Tricircle - tags: - - team:single-vendor deliverables: tricircle: repos: @@ -3616,8 +3549,6 @@ tripleo: Develop and maintain tooling and infrastructure able to deploy OpenStack in production, using OpenStack itself wherever possible. url: https://wiki.openstack.org/wiki/TripleO - tags: - - team:single-vendor deliverables: ansible-role-container-registry: repos: @@ -3816,8 +3747,6 @@ watcher: Watcher's goal is to provide a flexible and scalable resource optimization service for multi-tenant OpenStack-based clouds. url: https://wiki.openstack.org/wiki/Watcher - tags: - - team:diverse-affiliation deliverables: watcher: repos: @@ -3846,8 +3775,6 @@ winstackers: into OpenStack. This includes producing projects containing Hyper-V / Windows related code, commonly used in OpenStack scenarios. url: https://wiki.openstack.org/wiki/Os-win - tags: - - team:single-vendor deliverables: os-win: repos: @@ -3893,8 +3820,6 @@ zaqar: scalable and highly-available manner, and to create and maintain associated Python libraries and documentation. url: https://wiki.openstack.org/wiki/Zaqar - tags: - - team:diverse-affiliation deliverables: python-zaqarclient: repos: @@ -3926,8 +3851,6 @@ zun: To provide an OpenStack containers service that integrates with various container technologies for managing application containers on OpenStack. url: https://wiki.openstack.org/wiki/Zun - tags: - - team:diverse-affiliation deliverables: python-zunclient: repos: diff --git a/reference/tags/index.rst b/reference/tags/index.rst index acf06e4c8..37bea4e2f 100644 --- a/reference/tags/index.rst +++ b/reference/tags/index.rst @@ -38,8 +38,6 @@ Team Description Tags :maxdepth: 1 status_maintenance-mode - team_diverse-affiliation - team_single-vendor Project Assertion Tags ====================== diff --git a/reference/tags/team_diverse-affiliation.rst b/reference/tags/team_diverse-affiliation.rst deleted file mode 100644 index b95eb15a0..000000000 --- a/reference/tags/team_diverse-affiliation.rst +++ /dev/null @@ -1,77 +0,0 @@ -:: - - This work is licensed under a Creative Commons Attribution 3.0 - Unported License. - http://creativecommons.org/licenses/by/3.0/legalcode - -.. _`tag-team:diverse-affiliation`: - -======================== -team:diverse-affiliation -======================== - -A project with this tag has achieved a level of diversity in the affiliation of -contributors that is indicative of a healthy collaborative project. This tag -exists in the 'team' category, which as the name implies, covers information -about the team itself. Another example of a tag that could exist in this -category is one that conveys the size of the team that is actively contributing. - - -Application to current teams -============================ - -It's worth pointing out that the criteria used for this tag is applied across -all git repositories managed by a team. - -.. tagged-projects:: team:diverse-affiliation - - -Script used to apply this tag: -http://git.openstack.org/cgit/openstack/governance/tree/tools/validate_tags.py - - -Rationale -========= - -We value having a broad base of contributors to a project for several reasons. -One such reason is that it's more risky to rely on a project controlled by a -single organization as the project will immediately come to a halt if that one -organization chooses to stop working on it. We also value a project where -priorities must be set and agreed upon in a community fashion instead of purely -controlled by a single organization. - - -Requirements -============ - -No one organization should represent a majority (>50%) and no two organizations -should represent >80% of any of the following: - -* the sum of all commits merged into any of the git repositories managed by the - team - -* the sum of all reviews done against patches submitted to any of the git - repositories managed by the team - -* the sum of all reviews done by active core reviewers against patches submitted - to any of the git repositories managed by the team - -* the union of the active memberships of the core review teams associated with - the git repositories managed by the team - -This tag is applied based on the `tools/teamstats.py` script. The output of this -script is then reviewed by the TC to verify it matches the reality. - -The timeline used for evaluation is based on the past 6 months, and should be -updated around the same time as the 6 month release. - -Based on how requirements are defined, this tag is only applicable for projects -where their primary deliverables are represented by commits and reviews in git. -An example of where this doesn't make sense is the release management team. - - -Deprecation -=========== - -There is no deprecation period required for this tag. It can be added or -removed at any time. diff --git a/reference/tags/team_single-vendor.rst b/reference/tags/team_single-vendor.rst deleted file mode 100644 index c487c479a..000000000 --- a/reference/tags/team_single-vendor.rst +++ /dev/null @@ -1,78 +0,0 @@ -:: - - This work is licensed under a Creative Commons Attribution 3.0 - Unported License. - http://creativecommons.org/licenses/by/3.0/legalcode - -.. _`tag-team:single-vendor`: - -================== -team:single-vendor -================== - -This tag communicates that a given project team is currently driven by a -single organization. - -This tag exists in the 'team' category, which as the name implies, -covers information about the team itself. - - -Application to current teams -============================ - -It's worth pointing out that the criteria used for this tag is applied across -all git repositories managed by a team. - -.. tagged-projects:: team:single-vendor - -Script used to apply this tag: -http://git.openstack.org/cgit/openstack/governance/tree/tools/validate_tags.py - - -Rationale -========= - -Knowing that a given project is produced by a team essentially from a single -organization is a critical factor in the decision to deploy a project, as it -changes the dynamics of who you trust to continue to deliver this project. - -In particular, such a project could be abandoned due to the budgeting -decisions of a single party. Additional steps (like engaging early on with -that single party) could be taken before investing significantly on such a -project. - - -Requirements -============ - -The tag applies to any project team where one organization represents >=90% of -any of the following over the prior six months: - -* the sum of all commits merged into any of the git repositories managed by the - team - -* the sum of all reviews done against patches submitted to any of the git - repositories managed by the team - -* the sum of all reviews done by active core reviewers against patches submitted - to any of the git repositories managed by the team - -* the union of the active members of the core review teams associated with the - git repositories managed by the team - -This tag is applied based on the `tools/teamstats.py` script. The output of this -script is then reviewed by the TC to verify it matches the reality. - -The application of this tag to new projects should be updated around the same -time as the 6 month release. But the removal of this tag should happen shortly -after it does not apply to a given project. - -Based on how requirements are defined, this tag is only applicable for projects -where their primary deliverables are represented by commits and reviews in git. - - -Deprecation -=========== - -There is no deprecation period required for this tag. It can be added or -removed at any time. diff --git a/tools/teamstats.py b/tools/teamstats.py deleted file mode 100644 index b5bddc5f2..000000000 --- a/tools/teamstats.py +++ /dev/null @@ -1,280 +0,0 @@ -#!/usr/bin/env python - -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import functools -import os -import sys -import time -import uuid - -import requests -import requests_cache -import yaml - -import base - -# Since the stackalytics is slow and we can call it twice, cache the results -requests_cache.install_cache(backend='memory', expire_after=60) - -s = requests.session() - -six_months = int(time.time() - 30*6*24*60*60) # 6 months ago - -# NOTE(flaper87): This value affects both, single-vendor and diverse-affiliation -# tags and it's been tuned to a reasonable enough threshold to measure reviews -# activeness. Changes to this value must be discussed separately. -MIN_PERCENTAGE_REVIEWS = 0.02 # 2% -MIN_REVIEWS = 30 -MIN_COMMITS = 6 - - -def _memoize(func): - cache = {} - - @functools.wraps(func) - def memoized(*args, **kwargs): - key = (args, tuple(kwargs.items())) - try: - return cache[key] - except KeyError: - cache[key] = func(*args, **kwargs) - return cache[key] - return memoized - - -@_memoize -def _get_number_of_commits(group, start_date=six_months): - commits = s.get('http://stackalytics.com/api/' - '1.0/stats/companies?metric=commits&release=all' - '&project_type=all&module=%s&start_date=%s' - % (group, start_date)).json() - return sum([company['metric'] for company in commits['stats']]) - - -@_memoize -def get_team_size_stats(team): - team_stats = {} - group = "%s-group" % team.lower() - commits_total = _get_number_of_commits(group) - min_percent = int(commits_total * MIN_PERCENTAGE_REVIEWS) - reviews = s.get('http://stackalytics.com/api/' - '1.0/stats/engineers?metric=marks&release=all' - '&start_date=%s&project_type=all' - '&module=%s' % (six_months, group)).json() - team_stats['active_reviewers'] = 0 - for eng in reviews['stats']: - if eng['metric'] >= MIN_REVIEWS or eng['metric'] >= min_percent: - team_stats['active_reviewers'] += 1 - - team_stats['active_committers'] = 0 - commits = s.get('http://stackalytics.com/api/' - '1.0/stats/engineers?metric=commits&release=all' - '&project_type=all&module=%s&start_date=%s' - % (group, six_months)).json() - for eng in commits['stats']: - if eng['metric'] >= MIN_COMMITS: - team_stats['active_committers'] += 1 - - return team_stats - - -@_memoize -def get_core_reviews_by_company(group): - # reviews by individual - commits_total = _get_number_of_commits(group) - min_percent = int(commits_total * MIN_PERCENTAGE_REVIEWS) - - reviews = s.get('http://stackalytics.com/api/' - '1.0/stats/engineers?metric=marks&release=all' - '&start_date=%s&project_type=all' - '&module=%s' % (six_months, group)).json() - companies = {} - for eng in reviews['stats']: - if eng['core'] != 'master': - continue - for stat in s.get('http://stackalytics.com/api/1.0/stats/' - 'companies?metric=marks&module=%s&user_id=%s&' - 'project_type=all&release=all&start_date=%s' % - (group, eng['id'], six_months)).json()['stats']: - company = stat['id'] - if company == '*independent': - # several independent reviewers are not working in one company - company = 'independent-%s' % uuid.uuid4() - - companies.setdefault(company, {'reviewers': 0, 'reviews': 0}) - - if eng['metric'] >= MIN_REVIEWS or eng['metric'] >= min_percent: - companies[company]['reviews'] += stat['metric'] - companies[company]['reviewers'] += 1 - - return companies - - -@_memoize -def get_diversity_stats(project): - team_stats = {} - # commits by company - group = "%s-group" % project.lower() - commit_resp = s.get('http://stackalytics.com/api/' - '1.0/stats/companies?metric=commits&release=all' - '&project_type=all&module=%s&start_date=%s' - % (group, six_months)) - if commit_resp.status_code == 404: - # The project in question doesn't have a group in stackalytics because - # it's part of a different group. Just look for it without the group - # suffix (e.g. during shade transition, there is no shade-group because - # the shade repo was in infra-group) - group = project.lower() - commit_resp = s.get('http://stackalytics.com/api/' - '1.0/stats/companies?metric=commits&release=all' - '&project_type=all&module=%s&start_date=%s' - % (group, six_months)) - commits = commit_resp.json() - # reviews by company - reviews = s.get('http://stackalytics.com/api/' - '1.0/stats/companies?metric=marks&release=all' - '&project_type=all&module=%s&start_date=%s' - % (group, six_months)).json() - core_reviews_by_company = get_core_reviews_by_company(group) - commits_total = sum([company['metric'] for company in commits['stats']]) - top2 = [ - commits['stats'][0]['metric'] if len(commits['stats']) > 0 else 0, - commits['stats'][1]['metric'] if len(commits['stats']) > 1 else 0, - ] - team_stats['commits_top'] = ( - (float(top2[0]) / commits_total * 100) if commits_total else 0) - team_stats['commits_top2'] = ( - (float(sum(top2)) / commits_total * 100) if commits_total else 0) - - reviews_total = sum([company['metric'] for company in reviews['stats']]) - top2 = [ - reviews['stats'][0]['metric'] if len(reviews['stats']) > 0 else 0, - reviews['stats'][1]['metric'] if len(reviews['stats']) > 1 else 0, - ] - team_stats['reviews_top'] = ( - (float(top2[0]) / reviews_total * 100) if reviews_total else 0) - team_stats['reviews_top2'] = ( - (float(sum(top2)) / reviews_total * 100) if reviews_total else 0) - core_review_values = [company['reviews'] for company in - core_reviews_by_company.values()] - if len(core_review_values) == 1: - core_review_values = [core_review_values[0], 0] - core_review_values.sort(reverse=True) - core_reviews_total = sum(core_review_values) - team_stats['core_reviews_top'] = ( - (float(core_review_values[0]) / core_reviews_total * 100) - if core_reviews_total else 0) - team_stats['core_reviews_top2'] = ( - ((float(core_review_values[0]) + float(core_review_values[1])) / - core_reviews_total * 100) if core_reviews_total else 0) - core_reviewers_values = [company['reviewers'] for company in - core_reviews_by_company.values()] - if len(core_reviewers_values) == 1: - core_reviewers_values = [core_reviewers_values[0], 0] - core_reviewers_values.sort(reverse=True) - core_reviewers_total = sum(core_reviewers_values) - team_stats['core_reviewers_top'] = ( - (float(core_reviewers_values[0]) / core_reviewers_total * 100) - if core_reviewers_total else 0) - team_stats['core_reviewers_top2'] = ( - ((float(core_reviewers_values[0]) + float(core_reviewers_values[1])) / - core_reviewers_total * 100) if core_reviewers_total else 0) - - return team_stats - - -def is_diverse(team): - team_stats = get_diversity_stats(team) - diversity = all(( - (team_stats['commits_top'] <= 50), - (team_stats['reviews_top'] <= 50), - (team_stats['core_reviews_top'] <= 50), - (team_stats['core_reviewers_top'] <= 50), - (team_stats['commits_top2'] <= 80), - (team_stats['reviews_top2'] <= 80), - (team_stats['core_reviews_top2'] <= 80), - (team_stats['core_reviewers_top2'] <= 80), - )) - return diversity - - -def is_single_vendor(team): - team_stats = get_diversity_stats(team) - multi_vendor = all(( - (team_stats['commits_top'] < 90), - (team_stats['reviews_top'] < 90), - (team_stats['core_reviews_top'] < 90), - (team_stats['core_reviewers_top'] < 90), - )) - return not multi_vendor - - -def print_diversity(team): - team_stats = get_diversity_stats(team) - print('%-18s (%.2f%% | %.2f%% | %.2f%% | %.2f%%)' % ( - team, team_stats['commits_top'], team_stats['reviews_top'], - team_stats['core_reviews_top'], team_stats['core_reviewers_top'])) - print('%-18s (%.2f%% | %.2f%% | %.2f%% | %.2f%%)' % ( - '', team_stats['commits_top2'], team_stats['reviews_top2'], - team_stats['core_reviews_top2'], team_stats['core_reviewers_top2'])) - - -def print_team_size(team): - team_stats = get_team_size_stats(team) - print('%-18s (%6s | %6s)' % ( - '', team_stats['active_committers'], - team_stats['active_reviewers'])) - - -class ValidateDiversity(base.ValidatorBase): - - @staticmethod - def validate(team): - """Return True of team should have 'team:diverse-affiliation'""" - return is_diverse(team) - - @staticmethod - def get_tag_name(): - return "team:diverse-affiliation" - - -class ValidateSingleVendor(base.ValidatorBase): - - @staticmethod - def validate(team): - """Return True of team should have 'team:single-vendor'""" - return is_single_vendor(team) - - @staticmethod - def get_tag_name(): - return "team:single-vendor" - - -def main(): - filename = os.path.abspath('reference/projects.yaml') - with open(filename, 'r') as f: - projects = [k for k in yaml.safe_load(f.read())] - projects.sort() - print(' (top commit % | top review % | top core review % | ' - 'top core reviewer %)') - print(' (top 2 commit % | top 2 review % | top 2 core review % | ' - 'top 2 core reviewer %)') - print(' (active committers | active reviewers)') - for project in projects: - print_diversity(project) - print_team_size(project) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/tools/validate_tags.py b/tools/validate_tags.py deleted file mode 100755 index 5749098fb..000000000 --- a/tools/validate_tags.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env python - -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" validate tag applications in projects.yaml - -Validate the application of tags that can be pragmatically applied. - -Note: Does not automatically update projects.yaml since doing so can reformat -and reorder projects.yaml - -""" - -import teamstats - -import requests -import yaml - -import os -import sys - -from six.moves.urllib import parse -# List of modules to validate team based tags -team_validators = [ - teamstats.ValidateDiversity, - teamstats.ValidateSingleVendor, -] - -# List of modules to validate repository based tags -repo_validators = [] - - -def main(): - script_path = os.path.abspath(os.path.dirname(__file__)) - filename = os.path.abspath(os.path.join(script_path, - '../reference/projects.yaml')) - if not os.path.isfile(filename): - sys.exit("Projects.yaml was not found at %s" % (filename)) - with open(filename, 'r') as f: - teams = yaml.safe_load(f.read()) - for team in teams: - # Check team based tags - for validator in team_validators: - validate(team, teams[team], validator) - # Check deliverable based tags - for name, deliverable in teams[team]['deliverables'].items(): - for repo in deliverable['repos']: - if not repo_exists(repo): - continue - for validator in repo_validators: - validate(repo, deliverable, validator) - - -def validate(name, data, validator): - tag_name = validator.get_tag_name() - contains_tag = any([tag_name == tag for tag in - data.get('tags', [])]) - if validator.validate(name): - # should contain tag - if not contains_tag: - print_tag_missing(name, tag_name) - else: - # should not contain tag - if contains_tag: - print_bad_tag(name, tag_name) - - -def repo_exists(repo): - """Sometimes the governance docs can get out of sync with repo names.""" - response = requests.get( - 'https://review.openstack.org:443/projects/%s/' % - parse.quote_plus(repo)) - # strip off first few chars because 'the JSON response body starts with - # a magic prefix line that must be stripped before feeding the rest of - # the response body to a JSON parser' - # https://review.openstack.org/Documentation/rest-api.html - if response.status_code == 404: - return False - return True - - -def print_tag_missing(name, tag): - print("* %s should have the tag '%s'" % (name, tag)) - - -def print_bad_tag(name, tag): - print("* %s should not have the tag '%s'" % (name, tag)) - -if __name__ == '__main__': - sys.exit(main())