Merge "Remove team diversity tags"
This commit is contained in:
commit
0a90d65df3
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
@ -286,8 +282,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:
|
||||
|
@ -326,8 +320,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:
|
||||
|
@ -376,8 +368,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:
|
||||
|
@ -538,8 +528,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:
|
||||
|
@ -665,8 +653,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:
|
||||
|
@ -1026,8 +1012,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:
|
||||
|
@ -1516,8 +1500,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:
|
||||
|
@ -1636,8 +1618,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:
|
||||
|
@ -1692,8 +1672,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:
|
||||
|
@ -1764,8 +1742,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:
|
||||
|
@ -1795,8 +1771,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:
|
||||
|
@ -1839,8 +1813,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:
|
||||
|
@ -1906,8 +1878,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:
|
||||
|
@ -2027,8 +1997,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:
|
||||
|
@ -2116,8 +2084,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:
|
||||
|
@ -2206,8 +2172,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:
|
||||
|
@ -2461,8 +2425,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:
|
||||
|
@ -2615,8 +2577,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:
|
||||
|
@ -2643,8 +2603,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:
|
||||
|
@ -2682,8 +2640,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:
|
||||
|
@ -2902,8 +2858,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:
|
||||
|
@ -3085,8 +3039,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:
|
||||
|
@ -3106,8 +3058,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:
|
||||
|
@ -3233,8 +3183,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:
|
||||
|
@ -3263,8 +3211,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:
|
||||
|
@ -3333,7 +3279,6 @@ searchlight:
|
|||
cloud resources.
|
||||
url: https://wiki.openstack.org/wiki/Searchlight
|
||||
tags:
|
||||
- team:diverse-affiliation
|
||||
- status:maintenance-mode
|
||||
deliverables:
|
||||
searchlight:
|
||||
|
@ -3361,8 +3306,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:
|
||||
|
@ -3400,8 +3343,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:
|
||||
|
@ -3428,8 +3369,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:
|
||||
|
@ -3458,8 +3397,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:
|
||||
|
@ -3474,8 +3411,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:
|
||||
|
@ -3597,8 +3532,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:
|
||||
|
@ -3618,8 +3551,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:
|
||||
|
@ -3818,8 +3749,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:
|
||||
|
@ -3848,8 +3777,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:
|
||||
|
@ -3895,8 +3822,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:
|
||||
|
@ -3928,8 +3853,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:
|
||||
|
|
|
@ -38,8 +38,6 @@ Team Description Tags
|
|||
:maxdepth: 1
|
||||
|
||||
status_maintenance-mode
|
||||
team_diverse-affiliation
|
||||
team_single-vendor
|
||||
|
||||
Project Assertion Tags
|
||||
======================
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
|
@ -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('<Team> (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())
|
|
@ -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())
|
Loading…
Reference in New Issue