-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Damaged graph #11981
Comments
Could you give more details? |
The graph is disappearing after doing some merges or pushing local branches. It's the only thing we know. We found 5/100+ of our repos with the same state as on the try.gitea.io. |
Looking at the browser inspector console I see:
|
running with:
Line 519 (to the browser) appears to match up with: gitea/web_src/js/vendor/gitgraph.js Line 380 in d31a9c5
|
It appears the problem is that the git graph is not in the format that this js function seems to expect. The js seems to expect the use of underscores and not hyphens... If I bodge in code to handle hyphens the problem goes away. Now I'm not sure why this is different but my build of git 1.7.2 appears to use hyphens so perhaps this has always been broken?! Edit: I suspect it has |
There is a bug in web_src/js/vendor/gitgraph.js whereby it fails to handle multiple merges in a single commit correctly. This PR adds changes to make this work. Fix go-gitea#11981 Signed-off-by: Andrew Thornton <art27@cantab.net>
* Handle multiple merges in gitgraph.js There is a bug in web_src/js/vendor/gitgraph.js whereby it fails to handle multiple merges in a single commit correctly. This PR adds changes to make this work. Fix #11981 Signed-off-by: Andrew Thornton <art27@cantab.net> * Update web_src/js/vendor/gitgraph.js
* Handle multiple merges in gitgraph.js There is a bug in web_src/js/vendor/gitgraph.js whereby it fails to handle multiple merges in a single commit correctly. This PR adds changes to make this work. Fix go-gitea#11981 Signed-off-by: Andrew Thornton <art27@cantab.net> * Update web_src/js/vendor/gitgraph.js
Another damaged graph: https://try.gitea.io/ahaha/gitgraph/graph |
Hello! 2/5 of our repos still damaged. @ahttvy may be right
|
sigh... |
After fixing the initial problem in go-gitea#11981 another problem has come to light... Fix go-gitea#11981 (part 2) Signed-off-by: Andrew Thornton <art27@cantab.net>
OK so that's a different but related issue - here's another bugfix... I suspect this code needs to be completely rewritten. |
* Fix gitgraph branch continues after merge After fixing the initial problem in #11981 another problem has come to light... Fix #11981 (part 2) Signed-off-by: Andrew Thornton <art27@cantab.net> * Update web_src/js/vendor/gitgraph.js * Apply suggestions from code review Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
The last one - https://try.gitea.io/ahaha/qtconnectivity/graph |
Ugh this one is a bit more difficult. I'll have to take a deeper look to understand what the code is doing. |
The below patch will prevent the graph from erroring out but doesn't fix the underlying problem: diff --git a/web_src/js/vendor/gitgraph.js b/web_src/js/vendor/gitgraph.js
index 0cf5d0f75..7a5777598 100644
--- a/web_src/js/vendor/gitgraph.js
+++ b/web_src/js/vendor/gitgraph.js
@@ -376,7 +376,18 @@ export default function gitGraph(canvas, rawGraphList, config) {
flows.splice(colomnIndex, 0, genNewFlow());
}
- color = flows[colomnIndex].color;
+ if (colomnIndex < flows.length) {
+ color = flows[colomnIndex].color;
+ } else {
+ console.error({
+ message: "Missing flow!",
+ colomnIndex,
+ colomn,
+ prevColomn,
+ flowSwapPos,
+ });
+ color = "#000";
+ }
switch (colomn) {
case '-': |
* Fix gitgraph branch continues after merge After fixing the initial problem in go-gitea#11981 another problem has come to light... Fix go-gitea#11981 (part 2) Signed-off-by: Andrew Thornton <art27@cantab.net> * Update web_src/js/vendor/gitgraph.js * Apply suggestions from code review Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
OK I think this 3rd problem is sufficiently difficult to solve that it might be that I just have to rewrite this code. |
Backport #12044 * Fix gitgraph branch continues after merge After fixing the initial problem in #11981 another problem has come to light... Fix #11981 (part 2) Signed-off-by: Andrew Thornton <art27@cantab.net> * Update web_src/js/vendor/gitgraph.js * Apply suggestions from code review Co-authored-by: silverwind <me@silverwind.io>
So I think I will have to rewrite the gitgraph.js to look something like this to fix this final problem: Broken JS/* This is a customized version of https://github.com/bluef/gitgraph.js/blob/master/gitgraph.js
Changes include conversion to ES6 and linting fixes */
/*
* @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD 3-Clause
* Copyright (c) 2011, Terrence Lee <kill889@gmail.com>
* All rights reserved.
*
* 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.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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 <COPYRIGHT HOLDER> 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.
*/
export default function gitGraph(canvas, rawGraphList, config) {
if (!canvas.getContext) {
return;
}
if (typeof config === 'undefined') {
config = {
unitSize: 20,
lineWidth: 3,
nodeRadius: 4
};
}
const nextFlows = [];
const graphList = [];
const ctx = canvas.getContext('2d');
const devicePixelRatio = window.devicePixelRatio || 1;
const backingStoreRatio = ctx.webkitBackingStorePixelRatio
|| ctx.mozBackingStorePixelRatio
|| ctx.msBackingStorePixelRatio
|| ctx.oBackingStorePixelRatio
|| ctx.backingStorePixelRatio || 1;
const ratio = devicePixelRatio / backingStoreRatio;
const init = function () {
let maxWidth = 0;
let i;
const l = rawGraphList.length;
let row;
let midStr;
for (i = 0; i < l; i++) {
midStr = rawGraphList[i].replace(/\s+/g, ' ').replace(/^\s+|\s+$/g, '');
midStr = midStr.replace(/(--)|(-\.)/g,'-')
maxWidth = Math.max(midStr.replace(/(_|\s)/g, '').length, maxWidth);
row = midStr.split('');
graphList.unshift(row);
}
const width = maxWidth * config.unitSize;
const height = graphList.length * config.unitSize;
canvas.width = width * ratio;
canvas.height = height * ratio;
canvas.style.width = `${width}px`;
canvas.style.height = `${height}px`;
ctx.lineWidth = config.lineWidth;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.scale(ratio, ratio);
};
const genRandomStr = function () {
const chars = '0123456789ABCDEF';
const stringLength = 6;
let randomString = '', rnum, i;
for (i = 0; i < stringLength; i++) {
rnum = Math.floor(Math.random() * chars.length);
randomString += chars.substring(rnum, rnum + 1);
}
return randomString;
};
const findFlow = function (id) {
let i = nextFlows.length;
while (i-- && nextFlows[i].id !== id);
return i;
};
const findColomn = function (symbol, row) {
let i = row.length;
while (i-- && row[i] !== symbol);
return i;
};
const findBranchOut = function (row) {
if (!row) {
return -1;
}
let i = row.length;
while (i--
&& !(row[i - 1] && row[i] === '/' && row[i - 1] === '|')
&& !(row[i - 2] && row[i] === '_' && row[i - 2] === '|'));
return i;
};
const findLineBreak = function (row) {
if (!row) {
return -1;
}
let i = row.length;
while (i--
&& !(row[i - 1] && row[i - 2] && row[i] === ' ' && row[i - 1] === '|' && row[i - 2] === '_'));
return i;
};
const genNewFlow = function () {
let newId;
do {
newId = genRandomStr();
} while (findFlow(newId) !== -1);
return { id: newId, color: `#${newId}` };
};
// Draw methods
const drawLine = function (moveX, moveY, lineX, lineY, color) {
ctx.strokeStyle = color;
ctx.beginPath();
ctx.moveTo(moveX, moveY);
ctx.lineTo(lineX, lineY);
ctx.stroke();
};
const drawLineRight = function (x, y, color) {
drawLine(x, y + config.unitSize / 2, x + config.unitSize, y + config.unitSize / 2, color);
};
const drawLineUp = function (x, y, color) {
drawLine(x, y + config.unitSize / 2, x, y - config.unitSize / 2, color);
};
const drawNode = function (x, y, color) {
ctx.strokeStyle = color;
drawLineUp(x, y, color);
ctx.beginPath();
ctx.arc(x, y, config.nodeRadius, 0, Math.PI * 2, true);
ctx.fill();
};
const drawLineIn = function (x, y, color) {
drawLine(x + config.unitSize, y + config.unitSize / 2, x, y - config.unitSize / 2, color);
};
const drawLineOut = function (x, y, color) {
drawLine(x, y + config.unitSize / 2, x + config.unitSize, y - config.unitSize / 2, color);
};
const draw = function (graphList) {
let x, y, i;
y = (canvas.height / ratio) - config.unitSize * 0.5;
let flows = new Array(graphList[0].length);
// Generate nextFlows for the first row - this is guaranteed to be: "(\| )*(\*)( \|)*"
for (i = 0; i < graphList[0].length; i++) {
if (graphList[0][i] === ' ') {
continue;
}
flows[i] = genNewFlow();
}
// Draw the first row
for (let idx = 0; idx < graphList[0].length; idx++) {
x = config.unitSize * 0.5 * (idx + 1);
const column = graphList[0][idx];
switch (column) {
case '*':
drawNode(x, y, flows[idx].color);
break;
case ' ':
break;
case '|':
drawLineUp(x, y, flows[idx].color);
break;
default:
console.error(`Unexpected symbol in first row[${idx}] = '${column}'`);
}
}
for (i = 1; i < graphList.length; i++) {
// Done previous row - step up the row
y -= config.unitSize;
const currentRow = graphList[i];
const prevRow = graphList[i-1];
let nextFlows = new Array(currentRow.length);
for (let idx = 0; idx < currentRow.length; idx++) {
switch (currentRow[idx]) {
case '|':
case '*':
if (idx+1 < currentRow.length &&
(currentRow[idx+1] === '/' || currentRow[idx+1] === '_') &&
idx < prevRow.length &&
(prevRow[idx] === '|' || prevRow[idx] === '*') &&
prevRow[idx-1] === '/' ) {
// If ' |/' keep the '|' flow
// '/|'
nextFlows[idx] = flows[idx];
} else if (idx+1 < currentRow.length &&
(currentRow[idx+1] === '/' || currentRow[idx+1] === '_') &&
idx -1 < prevRow.length &&
prevRow[idx-1] === '/') {
// If ' |/' take the '/' flow
// '/ ?'
nextFlows[idx] = flows[idx-1];
flows[idx-1] = genNewFlow();
} else if (idx - 1 < prevRow.length &&
prevRow[idx-1] === '/') {
// if ' |' take the '/' flow
// '/ '
nextFlows[idx] = flows[idx-1];
flows[idx-1] = genNewFlow();
} else if (idx < prevRow.length &&
(prevRow[idx] === '|' || prevRow[idx] === '*')) {
// If '|' OR '|' take the '|' flow
// '|' '*'
nextFlows[idx] = flows[idx];
flows[idx] = genNewFlow();
} else if (idx +1 < prevRow.length &&
prevRow[idx+1] === '\\') {
// If '| ' keep the '\' flow
// ' \'
nextFlows[idx] = flows[idx + 1];
} else {
// else just create a new flow - probably this is an error...
nextFlows[idx] = genNewFlow();
}
break;
case '/':
if (idx > 0 &&
currentRow[idx-1] === '_') {
// if '_/' keep the '_' flow
nextFlows[idx] = nextFlows[idx-1];
} else if (idx > 1 &&
(currentRow[idx-1] === '|' || currentRow[idx-1] === '*') &&
currentRow[idx-2] === '_') {
// If '_|/' keep the '_' flow
nextFlows[idx] = nextFlows[idx-2];
} else if (i > 1 &&
currentRow[idx-1] === '|' &&
idx-2 < prevRow.length &&
prevRow[idx-2] === '/') {
// If '?|/' keep the '/' flow - ('|' will have caused regeneration as necessary)
// '/??'
nextFlows[idx] = flows[idx-2];
} else if (idx > 0 &&
currentRow[idx-1] === ' ' &&
idx-1 < prevRow.length &&
prevRow[idx-1] === '/') {
// If ' /' - keep the '/' flow, but transform to '|' due to our spacing
// '/ '
nextFlows[idx] = flows[idx-1];
currentRow[idx] = '|';
} else if (idx > 0 &&
currentRow[idx-1] === ' ' &&
idx-1 < prevRow.length &&
prevRow[idx-1] === '|') {
// If ' /' - keep the '|' flow
// '| '
nextFlows[idx] = flows[idx-1];
} else if (idx < prevRow.length &&
prevRow[idx] === '\\') {
// If '/' <- Not sure this ever happens... but keep the '\' flow
// '\'
nextFlows[idx] = flows[idx];
} else {
// Otherwise just generate a new flow and wait for bug-reports...
nextFlows[idx] = genNewFlow();
}
break;
case '\\':
if (prevRow[idx] === '/') {
// If '\?' take the '/' flow
// '/?'
nextFlows[idx] = flows[idx];
flows[idx] = genNewFlow();
} else if (idx+1 < prevRow.length &&
prevRow[idx+1] === '\\') {
// If '\?' take the '\' flow and reassign to |
// ' \'
nextFlows[idx] = flows[idx+1];
currentRow[idx] = '|';
flows[idx+1] = genNewFlow(); // <- prevents us having to think too hard about '\|/'
} else if (idx+1 < prevRow.length &&
(prevRow[idx+1] === '|' || prevRow[idx+1] === '*')) {
// If '\?' take the '|' flow
// ' |'
nextFlows[idx] = flows[idx+1];
flows[idx+1] = genNewFlow(); // <- prevents us having to think too hard about '\|/'
} else {
// Otherwise just generate a new flow and wait for bug-reports...
nextFlows[idx] = genNewFlow();
}
break;
case '_':
if (idx > 0 &&
currentRow[idx-1] === '_') {
// if '__' keep the '_' flow
nextFlows[idx] = nextFlows[idx-1];
} else if (idx > 1 &&
currentRow[idx-1] === '|' &&
currentRow[idx-2] === '_') {
// if '_|_' keep the '_' flow
nextFlows[idx] = nextFlows[idx-2];
} else if (idx > 0 &&
idx-1 < prevRow.length &&
prevRow[idx-1] === '/') {
// if ' _' - keep the '/' flow
// '/ '
nextFlows[idx] = flows[idx-1];
} else if (idx > 1 &&
idx-2 < prevRow.length &&
prevRow[idx-2] === '/') {
// if ' |_' - keep the '/' flow
// '/? '
nextFlows[idx] = flows[idx-2];
} else {
// There really shouldn't be another way of doing this - generate and wait for bug-reports...
nextFlows[idx] = genNewFlow();
}
break;
case '-': {
// This is: ------.
// /|\
// Find the end of the '-':
let originalIdx = idx;
for (;idx < currentRow.length && currentRow[idx] === '-'; idx++);
if (currentRow[idx] !== '.') {
// It really should end in a '.' but this one doesn't...
// Step back
idx--;
// Generate a new flow and await bug-reports...
nextFlows[idx] = genNewFlow();
// Assign all of the '-' to the same flow.
for (;originalIdx<idx;originalIdx++) {
nextFlows[originalIdx] = nextFlows[idx];
}
} else {
// We have a sensible ----.
// Choose our flow either /, |, or \
let flow;
if (idx-1 < prevRow.length && prevRow[idx-1] == '/') {
flow = flows[idx-1];
} else if (idx < prevRow.length && prevRow[idx] == '|') {
flow = flows[idx];
} else if (idx+1 < prevRow.length && prevRow[idx] == '\\') {
flow = flows[idx+1];
} else {
// Again unexpected so let's generate and wait the bug-report
flow = genNewFlow();
}
// Assign all of the rest of the ----. to this flow.
for (;originalIdx<idx+1;originalIdx++) {
nextFlows[originalIdx] = flow;
}
}
}
break;
case ' ':
// spaces don't get no flows
break;
default:
// Unexpected so let's generate a new flow and wait for bug-reports
flows[idx] = genNewFlow();
}
}
for (let idx = 0; idx < currentRow.length; idx++) {
x = config.unitSize * 0.5 * (idx + 1);
switch (currentRow[idx]) {
case '-':
case '.':
case '_':
drawLineRight(x - 0.5 *config.unitSize, y, nextFlows[idx].color);
break;
case '*':
drawNode(x, y, nextFlows[idx].color);
break;
case '|':
drawLineUp(x, y, nextFlows[idx].color);
break;
case '/':
drawLineOut(x - 0.5 *config.unitSize, y, nextFlows[idx].color);
break;
case '\\':
drawLineIn(x - 0.5 *config.unitSize, y, nextFlows[idx].color);
break;
case ' ':
break;
default:
console.error('Unknown symbol', currentRow[idx], nextFlows[idx] ? nextFlows[idx].color: '');
}
}
flows = nextFlows
}
};
init();
draw(graphList);
}
// @end-license The above was an example not a complete fix. |
The current vendored gitgraph.js is no longer maintained and is difficult to understand, fix and maintain. This PR completely rewrites its logic - hopefully in a clearer fashion and easier to maintain. It also includes @silverwind's improvements of coloring the commit dots and preventing the flash of incorrect content. Further changes to contemplate in future will be abstracting out of the flows to an object, storing the involved commit references on the flows etc. However, this is probably a required step for this. Replaces go-gitea#12131 Fixes go-gitea#11981 (part 3) Signed-off-by: Andrew Thornton <art27@cantab.net>
The current vendored gitgraph.js is no longer maintained and is difficult to understand, fix and maintain. This PR completely rewrites its logic - hopefully in a clearer fashion and easier to maintain. It also includes @silverwind's improvements of coloring the commit dots and preventing the flash of incorrect content. Further changes to contemplate in future will be abstracting out of the flows to an object, storing the involved commit references on the flows etc. However, this is probably a required step for this. Replaces #12131 Fixes #11981 (part 3) Signed-off-by: Andrew Thornton <art27@cantab.net>
* Handle multiple merges in gitgraph.js There is a bug in web_src/js/vendor/gitgraph.js whereby it fails to handle multiple merges in a single commit correctly. This PR adds changes to make this work. Fix go-gitea#11981 Signed-off-by: Andrew Thornton <art27@cantab.net> * Update web_src/js/vendor/gitgraph.js
* Fix gitgraph branch continues after merge After fixing the initial problem in go-gitea#11981 another problem has come to light... Fix go-gitea#11981 (part 2) Signed-off-by: Andrew Thornton <art27@cantab.net> * Update web_src/js/vendor/gitgraph.js * Apply suggestions from code review Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
The current vendored gitgraph.js is no longer maintained and is difficult to understand, fix and maintain. This PR completely rewrites its logic - hopefully in a clearer fashion and easier to maintain. It also includes @silverwind's improvements of coloring the commit dots and preventing the flash of incorrect content. Further changes to contemplate in future will be abstracting out of the flows to an object, storing the involved commit references on the flows etc. However, this is probably a required step for this. Replaces go-gitea#12131 Fixes go-gitea#11981 (part 3) Signed-off-by: Andrew Thornton <art27@cantab.net>
For anyone watching this I've just merged another rework of the GitGraph rendering that has moved its rendering to the server. |
Description
We have damaged graph on some projects. This is very disturbing. Thanks.
Screenshots
The text was updated successfully, but these errors were encountered: