@samitouri / QOS-React / commits / dbd9c4b205

Introduce facts-tracker (#7747)

* Introduce facts-tracker We want to be able to track various things like number of files that are flowified, number of tests passing with Fiber... This introduces a tool that lets you do that. The API is very simple, you execute the script with a list of tuples [key value] and it's going to create a `facts` branch and put a txt file for each fact and values over time. ``` node scripts/facts-tracker/index.js \ "flow-files" "$COUNT_WITH_FLOW/$COUNT_ALL_FILES" ``` Test Plan: This is tricky to test because Travis only exposes the private variables (github token) when it processes a committed file and not on branches. The reason is that otherwise anyone could send a pull requests that does `echo $GITHUB_TOKEN` and steal your token. Given this constraint, I did all the work using two of my repos: - https://github.com/vjeux/facts-tracker - https://github.com/vjeux/facts-tracker-test and am sending this pull request that should work as is /fingers crossed/, but we won't be able to test it out until it is committed. Note that once this lands, I'm going to kill those two repos. * Update with all the suggested changes * Branch on a flow type in travis.yml * Use $GITHUB_TOKEN * properly escape it

Christopher Chedeau committed Sep 26, 2016 at 12:58 UTC dbd9c4b205321b9d881966256f9b7203fc794277
2 files changed +188
.travis.yml
+10
@@ -79,6 +79,16 @@ script:
79 ./node_modules/.bin/grunt jest:normal
80 git checkout -- src/renderers/dom/shared/ReactDOMFeatureFlags.js
81 ./node_modules/.bin/gulp react:extract-errors
82 + elif [ "$TEST_TYPE" = flow ]; then
83 + set -e
84 + ./node_modules/.bin/grunt flow
85 +
86 + ALL_FILES=`find src -name '*.js' | grep -v umd/ | grep -v __tests__ | grep -v __mocks__`
87 + COUNT_ALL_FILES=`echo $ALL_FILES | wc -l`
88 + COUNT_WITH_FLOW=`grep '@flow' $ALL_FILES | perl -pe 's/:.+//' | wc -l`
89 + node scripts/facts-tracker/index.js \
90 + "flow-files" "$COUNT_WITH_FLOW/$COUNT_ALL_FILES"
91 +
92 else
93 ./node_modules/.bin/grunt $TEST_TYPE
94 fi
scripts/facts-tracker/index.js new
+178
@@ -0,0 +1,178 @@
1 +#!/usr/bin/env node
2 +
3 +/**
4 + * Copyright (c) 2013-present, Facebook, Inc.
5 + * All rights reserved.
6 + *
7 + * This source code is licensed under the BSD-style license found in the
8 + * LICENSE file in the root directory of this source tree. An additional grant
9 + * of patent rights can be found in the PATENTS file in the same directory.
10 + */
11 +
12 +'use strict';
13 +
14 +var fs = require('fs');
15 +var path = require('path');
16 +var execSync = require('child_process').execSync;
17 +
18 +function escape(value) {
19 + return '\'' + value.replace(/'/g, "'\\''") + '\'';
20 +}
21 +
22 +var cwd = null;
23 +function exec(command) {
24 + console.error('>', command.replace(process.env.GITHUB_TOKEN, '************'));
25 + return execSync(command, cwd ? {cwd: cwd} : undefined).toString();
26 +}
27 +
28 +var isInsideOfTravis = !!process.env.TRAVIS_REPO_SLUG;
29 +
30 +if (isInsideOfTravis) {
31 + if (process.env.TRAVIS_BRANCH !== 'master') {
32 + console.error('facts-tracker: Branch is not master, exiting...');
33 + process.exit(0);
34 + }
35 +
36 + if (process.env.TRAVIS_PULL_REQUEST !== 'false') {
37 + console.error('facts-tracker: This is a pull request, exiting...');
38 + process.exit(0);
39 + }
40 +
41 + if (!process.env.GITHUB_USER || !process.env.GITHUB_TOKEN) {
42 + console.error(
43 + 'In order to use facts-tracker, you need to configure a ' +
44 + 'few environment variables in order to be able to commit to the ' +
45 + 'repository. Follow those steps to get you setup:\n' +
46 + '\n' +
47 + 'Go to https://github.com/settings/tokens/new\n' +
48 + ' - Fill "Token description" with "facts-tracker for ' +
49 + process.env.TRAVIS_REPO_SLUG + '"\n' +
50 + ' - Check "public_repo"\n' +
51 + ' - Press "Generate Token"\n' +
52 + '\n' +
53 + 'In a different tab, go to https://travis-ci.org/' +
54 + process.env.TRAVIS_REPO_SLUG + '/settings\n' +
55 + ' - Make sure "Build only if .travis.yml is present" is ON\n' +
56 + ' - Fill "Name" with "GITHUB_TOKEN" and "Value" with the token you ' +
57 + 'just generated. Press "Add"\n' +
58 + ' - Fill "Name" with "GITHUB_USER" and "Value" with the name of the ' +
59 + 'account you generated the token with. Press "Add"\n' +
60 + '\n' +
61 + 'Once this is done, commit anything to the repository to restart ' +
62 + 'Travis and it should work :)'
63 + );
64 + process.exit(1);
65 + }
66 +
67 + exec(
68 + 'echo "machine github.com login $GITHUB_USER password $GITHUB_TOKEN"' +
69 + '> ~/.netrc'
70 + );
71 + exec(
72 + 'git config --global user.name ' +
73 + escape(process.env.GITHUB_USER_NAME || 'facts-tracker')
74 + );
75 + exec(
76 + 'git config --global user.email ' +
77 + escape(process.env.GITHUB_USER_EMAIL || 'facts-tracker@no-reply.github.com')
78 + );
79 +}
80 +
81 +if (process.argv.length <= 2) {
82 + console.error('Usage: facts-tracker <name1> <value1> <name2> <value2>...');
83 + process.exit(1);
84 +}
85 +
86 +function getRepoSlug() {
87 + if (isInsideOfTravis) {
88 + return process.env.TRAVIS_REPO_SLUG;
89 + }
90 +
91 + var remotes = exec('git remote -v').split('\n');
92 + for (var i = 0; i < remotes.length; ++i) {
93 + var match = remotes[i].match(/^origin\t[^:]+:([^\.]+).+\(fetch\)/);
94 + if (match) {
95 + return match[1];
96 + }
97 + }
98 +
99 + console.error('Cannot find repository slug, sorry.');
100 + process.exit(1);
101 +}
102 +
103 +var repoSlug = getRepoSlug();
104 +var currentCommitHash = exec('git rev-parse HEAD').trim();
105 +var currentTimestamp = new Date().toISOString()
106 + .replace('T', ' ')
107 + .replace(/\..+/, '');
108 +
109 +function checkoutFactsFolder() {
110 + var factsFolder = '../' + repoSlug.split('/')[1] + '-facts';
111 + if (!fs.existsSync(factsFolder)) {
112 + var escapedRepoURL;
113 + if (isInsideOfTravis) {
114 + escapedRepoURL = 'https://$GITHUB_TOKEN@github.com/' + escape(repoSlug) + '.git';
115 + } else {
116 + escapedRepoURL = escape('git@github.com:' + repoSlug + '.git');
117 + }
118 +
119 + exec(
120 + 'git clone ' +
121 + '--branch facts ' +
122 + '--depth=5 ' +
123 + escapedRepoURL + ' ' +
124 + escape(factsFolder)
125 + );
126 + }
127 +
128 + cwd = path.resolve(factsFolder);
129 + exec('git fetch');
130 + if (exec('git status --porcelain')) {
131 + console.error('facts-tracker: `git status` is not clean, aborting.');
132 + process.exit(1);
133 + }
134 + exec('git rebase origin/facts');
135 +}
136 +checkoutFactsFolder();
137 +
138 +for (var i = 2; i < process.argv.length; i += 2) {
139 + var name = process.argv[i].trim();
140 + var value = process.argv[i + 1];
141 + if (value.indexOf('\n') !== -1) {
142 + console.error(
143 + 'facts-tracker: skipping', name,
144 + 'as the value contains new lines:', value
145 + );
146 + continue;
147 + }
148 +
149 + var filename = name + '.txt';
150 + try {
151 + var lastLine = exec('tail -n 1 ' + escape(filename));
152 + } catch (e) {
153 + // ignore error
154 + }
155 + var lastValue = lastLine && lastLine
156 + .replace(/^[^\t]+\t[^\t]+\t/, '') // commit hash \t timestamp \t
157 + .slice(0, -1); // trailing \n
158 +
159 + if (value !== lastValue) {
160 + fs.appendFileSync(
161 + path.resolve(cwd, filename),
162 + currentCommitHash + '\t' + currentTimestamp + '\t' + value + '\n'
163 + );
164 + }
165 +
166 + console.log(name);
167 + console.log(lastValue);
168 + console.log(value);
169 +}
170 +
171 +if (exec('git status --porcelain')) {
172 + exec('git add --all');
173 + exec('git commit -m ' + escape('Adding facts for ' + currentCommitHash));
174 + exec('git push origin facts');
175 +} else {
176 + console.error('facts-tracker: nothing to update');
177 +}
178 +cwd = null;