CI Performance analysis tool
perfo is an app that shows build performance from CI providers.
You will need the following things properly installed on your computer.
git clone git@github.com:peopledoc/perfo
cd perfo
yarn
Note that perfo includes not only a front ember app, but also an express server
that is used to query CI providers for data and store user preferences.
To reduce strain on external CI APIs (and maybe avoid rate limiting), the server
caches data requested from them in a filesystem-based cache. You can control
that cache with environment variables.
You will need the following environment variables to run the app:
PERFO_CIRCLECI_TOKEN
: a CircleCI API tokenOptionally, you may also set the following environment variables:
PERFO_CACHE_VALIDITY
: the server cache validity in milliseconds; defaults toPERFO_CACHE_PRUNE_INTERVAL
: the interval at which the whole cache content isPERFO_DATA_DIR
: the path where the server stores cache and stored data;data
directory at the project rootPERFO_LOG_FORMAT
: format for morgan logs; defaults to dev
PERFO_MAX_BUILD_AGE
: maximum age (in milliseconds) of builds to show dataPERFO_ORG_FILTER
: if set, only make projects visible when their org is setPERFO_PORT
: TCP port the server listens on; only used in production (theember serve
or 4200 asPERFO_ROOT_URL
: the root URL where the app is served; defaults to /
ember serve
You will need a webserver that is capable of serving static files from a
directory and proxying requests to a locally-running HTTP server.
ember build --environment=production
PERFO_ROOT_URL
environment is set during the build to thedist
directory (or whichever directoryember build
to output into) at the root URL.server/standalone.js
with node 11+PERFO_DATA_DIR
localhost:PERFO_PORT
).perfo automatically displays a build duration graph for projects (with one line
per build job) over time. Users can also define custom graphs for each project.
To use custom graphs, your build jobs must generate JSON artifacts that contain
an array of data points, each data point being an object with a string label
and a numeric value
.
When defining a custom graph, users set the following properties:
When drawing the graph, perfo will look for all builds that match the job name
and have an artifact that matches the regexp. It will fetch data for all those
artifacts and draw a curve for each distinct label
value found in those.
For example, you could imagine having a custom graph drawing the evolution of
your static asset sizes over time by having a build job generate a JSON artifact
with the following content:
[
{ 'label': 'vendor.js', 'value': 12345 },
{ 'label': 'vendor.css', 'value': 23456 },
{ 'label': 'app.js', 'value': 34567 },
{ 'label': 'app.css', 'value': 45678 }
]
perfo comes with a CircleCI provider. You may add new providers to theserver/providers
directory and they will be used automatically by the server
(after a restart).
A provider is a module that exports a single provider factory function. This
function must return an object with the methods as described below.
All methods must be async
(or return a promise). Objects returned may have
additional keys than those specified below, but to ensure there are no name
clashes with properties that may be added later to the provider API, you must
prefix any “private” property with an underscore.
async info()
: return information about the provider.
Must return an object with the following keys:
account
: an identifier for the provider user (user ID, e-mail…)connected
: boolean indicating whether the provider is able to reach its dataicon
(optional): URL for an icon to display for the providername
: a human-readable name for the data sourceasync projects()
: return the list of projects available
Must return an array of project objects, with the following keys:
id
: a unique ID (within the scope of the provider) for the projectname
: a human-readable name for the projectbranches
: an array of branch names for the projectasync builds(project, branch)
: return the list of available builds for a
branch of a project
Parameters:
project
is the project IDbranch
is the branch nameMust return an array of build objects, with the following keys:
id
: a unique ID (within the scope of the project) for the buildjob
: a job name for the build (eg. “test”, “build”…)start
: the starting date for the build as an ISO stringduration
: the duration of the build in millisecondssubject
: the subject of this specific build (eg. a commit message)revision
: the VCS revision for this specific build (eg. a commit SHA-1)async customGraphData(project, branch, jobName, artifactMatches)
: return a
list of datasets to draw a custom graph for a branch of a project
Parameters:
project
is the project IDbranch
is the branch namejobName
is used to filter builds to extract data fromartifactRegex
is used to filter artifact names to extract data fromMust return an array of dataset objects, one per build that matches thejobName
parameter and has an artifact whose name matches artifactRegex
. If
several artifacts from a build match, use the first one.
Dataset objects have the following keys:
date
: start date for the buildsubject
, revision
: same values as the corresponding keys in the buildpoints
: data from the first matching artifact in the build; should be anlabel
and a numeric value
.Provider factories will receive an injections
object as their first parameter.
This object contains various services that providers may want to use, most
notably the following:
config
: configuration data
Contains the following keys:
orgFilter
: organization filter to filter the project listmaxBuildAge
: maximum age in milliseconds of project builds to considerasync cache(key, async getter())
: get data from the server cache
Looks for a cached value with key
as a key, and return it.
The key namespace is shared, so you should prefix your cache keys with the
provider name. Use path.join()
to build keys with several parts.
If the key is not available or the cache has expired, getter()
will be called
and its return value will be stored in the cache and returned.
store
: local filesystem-backed data store
Stores data on the filesystem in a directory structure as JSON files. Any data
you store should be JSON-serializable.
The key namespace is shared, so you should prefix your store keys with the
provider name. Use path.join()
to build keys with several parts.
The store has the following methods:
async getItem(key)
: gets an item from the store or return undefinedasync setItem(key, value)
: set an item in the store, overriding any existingasync delItem(key)
: remove an item from the storeasync keys(path = '')
: list all keys in the store in a given pathNote: using cache vs. store?
When requesting data from a remote CI provider API, you should use the cache
for resources that change over time (eg. project list, project builds) and
the store for resources that do not change (eg. payload for a specific build
artifact).
logger
: very simple logging facility
Has the following methods:
debug(item, ...)
: logs items to the consoleerror(context, error)
: logs an error to the consoleThis project is licensed under the MIT License.