WIP Group contributions by URL

This commit is contained in:
2026-07-26 14:08:02 +02:00
parent 606f5c9383
commit a7e017971a
6 changed files with 218 additions and 4 deletions
+4 -4
View File
@@ -5,14 +5,14 @@ import processContributionData from 'kredits-web/utils/process-contribution-data
const items = [];
const data = [
{ id: 1, contributorId: 1, confirmedAt: 1000, claimed: false, vetoed: false, amount: 1500, kind: 'dev' },
{ id: 1, contributorId: 1, confirmedAt: 1000, claimed: false, vetoed: false, amount: 1500, kind: 'dev', url: 'https://github.com/67P/kredits-contracts/pull/196' },
{ id: 2, contributorId: 1, confirmedAt: 1000, claimed: false, vetoed: false, amount: 5000, kind: 'ops' },
{ id: 3, contributorId: 2, confirmedAt: 1000, claimed: false, vetoed: false, amount: 1500, kind: 'ops' },
{ id: 3, contributorId: 2, confirmedAt: 1000, claimed: false, vetoed: false, amount: 1500, kind: 'ops', url: 'https://github.com/67P/kredits-contracts/pull/196' },
{ id: 4, contributorId: 2, confirmedAt: 1000, claimed: false, vetoed: false, amount: 1500, kind: 'docs' },
{ id: 5, contributorId: 1, confirmedAt: 1000, claimed: false, vetoed: false, amount: 5000, kind: 'design' },
{ id: 6, contributorId: 1, confirmedAt: 1000, claimed: false, vetoed: true, amount: 500, kind: 'dev' },
{ id: 7, contributorId: 3, confirmedAt: 2000, claimed: false, vetoed: false, amount: 5000, kind: 'dev' },
{ id: 8, contributorId: 1, confirmedAt: 2000, claimed: false, vetoed: false, amount: 1500, kind: 'community' },
{ id: 7, contributorId: 3, confirmedAt: 2000, claimed: false, vetoed: false, amount: 5000, kind: 'dev', url: 'https://gitea.kosmos.org/kredits/kredits-web/issues/231' },
{ id: 8, contributorId: 1, confirmedAt: 2000, claimed: false, vetoed: false, amount: 1500, kind: 'community', url: 'https://gitea.kosmos.org/kredits/kredits-web/issues/231' },
{ id: 9, contributorId: 3, confirmedAt: 2000, claimed: false, vetoed: true, amount: 1500, kind: 'docs' },
];
+72
View File
@@ -60,6 +60,78 @@ module('Unit | Service | kredits', function(hooks) {
assert.equal(service.contributorsSorted[1].name, 'Manuel', 'sorts by name');
});
test('#contributionsGrouped groups contributions sharing a url', function(assert) {
let service = this.owner.lookup('service:kredits');
service.set('contributors', contributors);
service.set('contributions', contributions);
const grouped = service.contributionsGrouped;
// 9 contributions, with ids 1+3 sharing a url and ids 7+8 sharing a url,
// so 7 groups total (2 grouped + 5 singletons).
assert.equal(grouped.length, 7, 'produces one group per unique key plus singletons');
const ghGroup = grouped.findBy('groupId', 'https://github.com/67P/kredits-contracts/pull/196');
assert.ok(ghGroup, 'github url group exists');
assert.ok(ghGroup.isGrouped, 'github group is flagged as grouped');
assert.equal(ghGroup.items.length, 2, 'github group has two contributions');
assert.deepEqual(ghGroup.contributorIds, [1, 2], 'github group lists both contributor ids');
assert.equal(ghGroup.contributors.length, 2, 'github group resolves both contributors');
assert.equal(ghGroup.totalAmount, 3000, 'github group sums amounts (1500 + 1500)');
assert.equal(ghGroup.kind, 'dev', 'github group takes kind from first item');
assert.equal(ghGroup.url, 'https://github.com/67P/kredits-contracts/pull/196');
const giteaGroup = grouped.findBy('groupId', 'https://gitea.kosmos.org/kredits/kredits-web/issues/231');
assert.ok(giteaGroup, 'gitea url group exists');
assert.ok(giteaGroup.isGrouped, 'gitea group is flagged as grouped');
assert.deepEqual(giteaGroup.contributorIds, [3, 1], 'gitea group lists both contributor ids');
assert.equal(giteaGroup.totalAmount, 6500, 'gitea group sums amounts (5000 + 1500)');
});
test('#contributionsGrouped treats manual contributions without url as singletons', function(assert) {
let service = this.owner.lookup('service:kredits');
service.set('contributors', contributors);
service.set('contributions', contributions);
const grouped = service.contributionsGrouped;
const singletons = grouped.filterBy('isGrouped', false);
// 5 contributions without a url: ids 2, 4, 5, 6, 9
assert.equal(singletons.length, 5, 'one singleton group per url-less contribution');
singletons.forEach(g => {
assert.equal(g.items.length, 1, 'singleton group has exactly one item');
assert.notOk(g.groupId, 'singleton group has a null/empty groupId');
});
});
test('#siblingContributions returns co-contributor contributions for the same url', function(assert) {
let service = this.owner.lookup('service:kredits');
service.set('contributors', contributors);
service.set('contributions', contributions);
const c1 = contributions.findBy('id', 1);
const siblings = service.siblingContributions(c1);
assert.equal(siblings.length, 1, 'contribution 1 has one sibling');
assert.equal(siblings[0].id, 3, 'the sibling is contribution 3');
});
test('#siblingContributions returns empty for manual contributions', function(assert) {
let service = this.owner.lookup('service:kredits');
service.set('contributors', contributors);
service.set('contributions', contributions);
const c2 = contributions.findBy('id', 2);
assert.deepEqual(service.siblingContributions(c2), [], 'no siblings for url-less contribution');
});
test('#siblingContributions returns empty for null contribution', function(assert) {
let service = this.owner.lookup('service:kredits');
service.set('contributors', contributors);
service.set('contributions', contributions);
assert.deepEqual(service.siblingContributions(null), [], 'no siblings for null');
});
test('#kreditsByContributor ignores unconfirmed contributions for contributors that are not loaded', function(assert) {
let service = this.owner.lookup('service:kredits');
service.set('contributors', contributors);
@@ -0,0 +1,48 @@
import { module, test } from 'qunit';
import EmberObject from '@ember/object';
import contributionGroupingKey from 'kredits-web/utils/contribution-grouping-key';
function makeContribution (url) {
return EmberObject.create({ url });
}
module('Unit | Utils | contribution-grouping-key', function() {
test('returns the url when present', function(assert) {
const c = makeContribution('https://github.com/67P/kredits-contracts/pull/196');
assert.equal(contributionGroupingKey(c), 'https://github.com/67P/kredits-contracts/pull/196');
});
test('returns the same key for identical github urls', function(assert) {
const a = makeContribution('https://github.com/67P/kredits-contracts/pull/196');
const b = makeContribution('https://github.com/67P/kredits-contracts/pull/196');
assert.equal(contributionGroupingKey(a), contributionGroupingKey(b));
});
test('returns the same key for identical gitea urls', function(assert) {
const a = makeContribution('https://gitea.kosmos.org/kredits/kredits-web/issues/231');
const b = makeContribution('https://gitea.kosmos.org/kredits/kredits-web/issues/231');
assert.equal(contributionGroupingKey(a), contributionGroupingKey(b));
});
test('returns different keys for different urls', function(assert) {
const a = makeContribution('https://github.com/67P/kredits-contracts/pull/196');
const b = makeContribution('https://github.com/67P/kredits-contracts/pull/197');
assert.notEqual(contributionGroupingKey(a), contributionGroupingKey(b));
});
test('returns null when url is empty', function(assert) {
const c = makeContribution('');
assert.equal(contributionGroupingKey(c), null);
});
test('returns null when url is null/undefined', function(assert) {
assert.equal(contributionGroupingKey(makeContribution(null)), null);
assert.equal(contributionGroupingKey(makeContribution(undefined)), null);
});
test('returns null when contribution is null/undefined', function(assert) {
assert.equal(contributionGroupingKey(null), null);
assert.equal(contributionGroupingKey(undefined), null);
});
});