diff --git a/dev/githubanalysis/README.md b/dev/githubanalysis/README.md index c45e63a52..64ce64207 100644 --- a/dev/githubanalysis/README.md +++ b/dev/githubanalysis/README.md @@ -32,3 +32,4 @@ Then, run: `dart run --enable-asserts bin/githubanalysis.dart` See also: * [Output from 2023-03-30](https://docs.google.com/spreadsheets/d/15hyxxapUmsK6J05X1goQ__9xJdzhJQM-BqsvM31-CTk/edit#gid=0) as a spreadsheet (with graphs). + * [Output from 2024-04-12](https://docs.google.com/spreadsheets/d/1h9IPF4ZKhfh4FbdzzqFFbznbGSxj-syVfruOIge9fac/edit?usp=sharing) as a spreadsheet (with graphs). diff --git a/dev/githubanalysis/lib/issue.dart b/dev/githubanalysis/lib/issue.dart index 195f7f81c..026771827 100644 --- a/dev/githubanalysis/lib/issue.dart +++ b/dev/githubanalysis/lib/issue.dart @@ -124,7 +124,8 @@ class FullIssue { ..writeln( 'Created by ${metadata.user!.login} on ${metadata.createdAt}, last updated on ${metadata.updatedAt}.', ); - if (metadata.isClosed) { + // Temporary workaround for https://github.com/SpinlockLabs/github.dart/issues/401 + if (metadata.isClosed || metadata.state.toUpperCase() == 'CLOSED') { result.writeln('Closed by ${metadata.closedBy?.login} on ${metadata.closedAt}.'); if (metadata.closedBy != null) { final User user = metadata.closedBy!; diff --git a/dev/githubanalysis/lib/main.dart b/dev/githubanalysis/lib/main.dart index e0a966508..6f49b4bf2 100644 --- a/dev/githubanalysis/lib/main.dart +++ b/dev/githubanalysis/lib/main.dart @@ -51,6 +51,16 @@ const Duration issueMaxAge = Duration(days: 365); const Set csvSpecials = {'\'', '"', ',', '\n'}; +// Temporary workaround for https://github.com/SpinlockLabs/github.dart/issues/401 +bool issueIsOpen(final FullIssue issue) { + return issue.metadata.isOpen || issue.metadata.state.toUpperCase() == 'OPEN'; +} + +// Temporary workaround for https://github.com/SpinlockLabs/github.dart/issues/401 +bool issueIsClosed(final FullIssue issue) { + return issue.metadata.isClosed || issue.metadata.state.toUpperCase() == 'CLOSED'; +} + Future full(final Directory cache, final GitHub github) async { try { // FETCH USER AND TEAM DATA @@ -273,13 +283,13 @@ Future full(final Directory cache, final GitHub github) async { } else { priorityResults.openedByNonTeam += 1; } - if (issue.metadata.isOpen) { + if (issueIsOpen(issue)) { priorityResults.open += 1; } else { priorityResults.closed += 1; if (issue.metadata.closedAt == null || issue.metadata.createdAt == null) { print( - 'WARNING: bogus open/close timeline data in ${issue.issueNumber}: opened at ${issue.metadata.createdAt}, closed at ${issue.metadata.closedAt}', + 'WARNING: bogus open/close timeline data in ${issue.issueNumber}: opened at ${issue.metadata.createdAt}, closed at ${issue.metadata.closedAt}, state: ${issue.metadata.state}', ); } else { final Duration timeOpen = issue.metadata.closedAt!.difference(issue.metadata.createdAt!); @@ -350,7 +360,7 @@ Future full(final Directory cache, final GitHub github) async { for (final FullIssue issue in allIssues.where((final FullIssue issue) => !issue.isPullRequest)) { verifyStringSanity(issue.metadata.state, csvSpecials); summary.write( - '${issue.repo.fullName},${issue.issueNumber},${issue.metadata.state},${issue.metadata.createdAt},${issue.metadata.user!.login},${issue.metadata.closedAt},${issue.metadata.closedBy?.login ?? (issue.isValid && issue.metadata.isClosed ? "" : "")},${issue.isValid && issue.metadata.isClosed ? issue.metadata.closedAt!.difference(issue.metadata.createdAt!).inMilliseconds / Duration.millisecondsPerDay : ""},${issue.metadata.updatedAt},${issue.priority ?? ""},${issue.labels.length},${issue.comments.length}', + '${issue.repo.fullName},${issue.issueNumber},${issue.metadata.state},${issue.metadata.createdAt},${issue.metadata.user!.login},${issue.metadata.closedAt},${issue.metadata.closedBy?.login ?? (issue.isValid && issueIsClosed(issue) ? "" : "")},${issue.isValid && issueIsClosed(issue) ? issue.metadata.closedAt!.difference(issue.metadata.createdAt!).inMilliseconds / Duration.millisecondsPerDay : ""},${issue.metadata.updatedAt},${issue.priority ?? ""},${issue.labels.length},${issue.comments.length}', ); for (final String reactionKind in sortedReactionKinds) { int count = 0; @@ -382,8 +392,8 @@ Future full(final Directory cache, final GitHub github) async { ..writeln(); if ((daysToTwentyVotes == null || daysToTwentyVotes > 60) && issue.labels.contains('new feature') && - (issue.metadata.isOpen || issue.metadata.closedAt!.difference(issue.metadata.createdAt!).inDays > 60)) { - if (issue.metadata.isOpen) { + (issueIsOpen(issue) || issue.metadata.closedAt!.difference(issue.metadata.createdAt!).inDays > 60)) { + if (issueIsOpen(issue)) { deadCount += 1; } else { zombieCount += 1; @@ -401,7 +411,7 @@ Future full(final Directory cache, final GitHub github) async { null: 0, for (final String priority in priorities) priority: 0, }; - for (final FullIssue issue in primaryIssues.where((final FullIssue issue) => issue.metadata.isClosed)) { + for (final FullIssue issue in primaryIssues.where(issueIsClosed)) { final int timeOpen = issue.metadata.closedAt!.difference(issue.metadata.createdAt!).inDays; final String? priority = issue.priority; closureTimeHistogramClosed.putIfAbsent(timeOpen, () => {}).update( @@ -466,7 +476,7 @@ Future full(final Directory cache, final GitHub github) async { for (final FullIssue issue in primaryIssues) { final String? priority = issue.priority; closureTimeTotalsAll[priority] = closureTimeTotalsAll[priority]! + 1; - final int timeOpen = issue.metadata.isClosed + final int timeOpen = issueIsClosed(issue) ? issue.metadata.closedAt!.difference(issue.metadata.createdAt!).inDays : maxDaysToClose + 1; closureTimeHistogramAll.putIfAbsent(timeOpen, () => {}).update( @@ -527,7 +537,7 @@ Future full(final Directory cache, final GitHub github) async { for (final FullIssue issue in allIssues.where((final FullIssue issue) => issue.isPullRequest)) { verifyStringSanity(issue.metadata.state, csvSpecials); summary.write( - '${issue.repo.fullName},${issue.issueNumber},${issue.metadata.user!.login},${issue.metadata.state},${issue.metadata.createdAt},${issue.metadata.closedAt},${issue.metadata.isClosed ? issue.metadata.closedAt!.difference(issue.metadata.createdAt!).inMilliseconds / Duration.millisecondsPerDay : ""},${issue.metadata.updatedAt},${issue.labels.length},${issue.comments.length}', + '${issue.repo.fullName},${issue.issueNumber},${issue.metadata.user!.login},${issue.metadata.state},${issue.metadata.createdAt},${issue.metadata.closedAt},${issueIsClosed(issue) ? issue.metadata.closedAt!.difference(issue.metadata.createdAt!).inMilliseconds / Duration.millisecondsPerDay : ""},${issue.metadata.updatedAt},${issue.labels.length},${issue.comments.length}', ); for (final String reactionKind in sortedReactionKinds) { int count = 0; @@ -596,7 +606,7 @@ Future full(final Directory cache, final GitHub github) async { forWeek(issue.metadata.createdAt)!.issues += 1; forWeek(issue.metadata.createdAt)!.priorityCount[issue.priority] = forWeek(issue.metadata.createdAt)!.priorityCount[issue.priority]! + 1; - if (issue.metadata.isOpen) { + if (issueIsOpen(issue)) { forWeek(issue.metadata.createdAt)!.remainingIssues += 1; } } @@ -653,10 +663,10 @@ Future full(final Directory cache, final GitHub github) async { final LabelData data = labels.putIfAbsent(label.name, () => LabelData(label.name)) ..all += 1 ..issues += 1; - if (issue.metadata.isOpen) { + if (issueIsOpen(issue)) { data.open += 1; } - if (issue.metadata.isClosed) { + if (issueIsClosed(issue)) { data.closed += 1; } if (now.difference(issue.metadata.updatedAt!) < const Duration(days: 52 * 7)) {