in jobs/reports/repositories.ts [339:499]
reasons: transformReasonsToArray(admin, repository.full_name),
});
}
}
}
}
// Send to org admins
const orgName = repository.organization.name;
const orgData = context.organizationData[orgName];
for (let i = 0; orgData && orgData.organizationContext && orgData.organizationContext.recipients && orgData.organizationContext.recipients.length && i < orgData.organizationContext.recipients.length; i++) {
repositoryContext.recipients.push(orgData.organizationContext.recipients[i]);
}
// Basic administrators info
basicRepository.administrators = 'None';
if (corporateAdministrators.length > 0) {
let caLink = 'mailto:' + corporateAdministrators.join(';') + '?subject=' + repository.full_name;
const peoplePlurality = corporateAdministrators.length > 1 ? 'people' : 'person';
basicRepository.administrators = {
link: caLink,
text: `${corporateAdministrators.length} ${peoplePlurality}`,
};
}
const actionEditCollaborators = {
link: githubDirectLink('editRepoPermissions', null, 'settings/collaboration'),
text: 'Permissions',
};
const actionDelete = {
link: githubDirectLink('repoDeleteOrTransfer', null, 'settings'),
text: 'Consider deleting or transferring',
};
const actionView = {
link: githubDirectLink('repoBrowse'),
text: 'Open',
};
const actionShip = {
link: githubDirectLink('repoShipIt', null, 'settings'),
text: 'Ship it',
};
const actionViewInPortal = context.config.urls ? {
link: reposDirectLink('repoDetails'),
text: 'Details',
} : null;
if (repositoryContext.administratorsByType.linked.length === 0 || repositoryContext.actionableAdministrators.length === 0) {
addEntityToIssueType(context, repositoryContext, 'noRepositoryAdministrators', basicRepository, actionEditCollaborators, actionViewInPortal);
}
let createdAt = repository.created_at ? moment(repository.created_at) : null;
if (createdAt) {
basicRepository.created = createdAt.format(simpleDateFormat);
}
let updatedAt = repository.updated_at ? moment(repository.updated_at) : null;
if (updatedAt) {
basicRepository.updated = updatedAt.format(simpleDateFormat);
}
let pushedAt = repository.pushed_at ? moment(repository.pushed_at) : null;
if (pushedAt) {
basicRepository.pushed = pushedAt.format(simpleDateFormat);
}
let mostRecentActivityMoment = createdAt;
let mostRecentActivity = 'Created';
if (updatedAt && updatedAt.isAfter(mostRecentActivityMoment)) {
mostRecentActivity = 'Updated';
mostRecentActivityMoment = updatedAt;
}
if (pushedAt && pushedAt.isAfter(mostRecentActivityMoment)) {
mostRecentActivity = 'Pushed';
mostRecentActivityMoment = pushedAt;
}
const twoYearsAgo = moment().subtract(2, 'years');
const oneYearAgo = moment().subtract(1, 'years');
const nineMonthsAgo = moment().subtract(9, 'months');
const thirtyDaysAgo = moment().subtract(30, 'days');
const thisWeek = moment().subtract(7, 'days');
const today = moment().subtract(1, 'days');
const ageInMonths = today.diff(createdAt, 'months');
if (ageInMonths > 0) {
basicRepository.ageInMonths = ageInMonths === 1 ? '1 month' : ageInMonths + ' months';
}
const monthsSinceUpdates = today.diff(mostRecentActivityMoment, 'months');
const timeAsString = monthsSinceUpdates + ' month' + (monthsSinceUpdates === 1 ? '' : 's');
basicRepository.recentActivity = monthsSinceUpdates < 1 ? 'Active' : `${timeAsString} (${mostRecentActivity})`;
if (mostRecentActivityMoment.isBefore(nineMonthsAgo)) {
basicRepository.abandoned = {
text: `${monthsSinceUpdates} months`,
color: 'red',
};
}
if (exemptRepositories && exemptRepositories[repository.id] && exemptRepositories[repository.id].approved && exemptRepositories[repository.id].days) {
const exemptionExpiresAt = moment(exemptRepositories[repository.id].approved)
.add(exemptRepositories[repository.id].days, 'days')
.subtract(2, 'weeks');
if (moment().isAfter(exemptionExpiresAt)) {
basicRepository.exemptionExpiresAt = exemptionExpiresAt.format(simpleDateFormat);
addEntityToIssueType(context, repositoryContext, 'expiringPrivateEngineeringExemptions', basicRepository, actionShip, actionDelete);
}
} else if (!repository.private && mostRecentActivityMoment.isBefore(twoYearsAgo)) {
addEntityToIssueType(context, repositoryContext, 'abandonedPublicRepositories', basicRepository, actionView, actionDelete);
} else if (repository.private && mostRecentActivityMoment.isBefore(twoYearsAgo)) {
addEntityToIssueType(context, repositoryContext, 'twoYearOldPrivateRepositories', basicRepository, actionView, actionDelete);
} else if (repository.private && createdAt.isBefore(oneYearAgo) && !privateEngineering) {
addEntityToIssueType(context, repositoryContext, 'oneYearOldPrivateRepositories', basicRepository, actionView, actionDelete);
} else if (repository.private && createdAt.isBefore(thirtyDaysAgo) && !privateEngineering) {
addEntityToIssueType(context, repositoryContext, 'privateRepositoriesLessThanOneYear', basicRepository, actionShip, actionDelete);
} else if (createdAt.isAfter(thisWeek) && !privateEngineering) {
// New public and private repos
const repositoryForManagerAndLawyer = shallowCloneWithAdditionalRecipients(basicRepository, repositoryContext.additionalRecipients);
if (createdAt.isAfter(today)) {
addEntityToIssueType(context, repositoryContext, 'NewReposToday', repositoryForManagerAndLawyer, actionView, actionViewInPortal);
}
// Always include in the weekly summary
addEntityToIssueType(context, repositoryContext, 'NewReposWeek', repositoryForManagerAndLawyer, actionView, actionViewInPortal);
}
// Alert on too many administrators, excluding private engineering organizations at this time
// NOTE: commenting out the "too many" notice for September 2017
//if (!privateEngineering && repositoryContext.actionableAdministrators.length > context.settings.tooManyRepoAdministrators) {
//addEntityToIssueType(context, repositoryContext, 'repositoryTooManyAdministrators', basicRepository, actionViewInPortal, actionEditCollaborators);
//}
if (context.settings.repoDelayAfter) {
await sleep(context.settings.repoDelayAfter);
}
}
function shallowCloneWithAdditionalRecipients(basicRepository: IBasicRepository, additionalRecipients) {
const clone = Object.assign({}, basicRepository);
if (additionalRecipients && additionalRecipients.length) {
clone.additionalRecipients = additionalRecipients;
}
return clone;
}
async function getNewRepoCreationInformation(context: IReportsContext, repositoryContext: IReportsRepositoryContext, basicRepository: IBasicRepository): Promise<void> {
const repository = repositoryContext.repository;
const thisWeek = moment().subtract(7, 'days');
let createdAt = repository.created_at ? moment(repository.created_at) : null;
let isBrandNew = createdAt.isAfter(thisWeek);
const repositoryMetadataProvider = context.providers.repositoryMetadataProvider;
if (!isBrandNew || !repositoryMetadataProvider) {
return;
}
const releaseTypeMapping = context.config && context.config.github && context.config.github.approvalTypes && context.config.github.approvalTypes.fields ? context.config.github.approvalTypes.fields.approvalIdsToReleaseType : null;
let approval = null;
try {
approval = await repositoryMetadataProvider.getRepositoryMetadata(repository.id);
} catch (approvalGetError) {
return;
}
if (!approval) {
return;
}
if (approval.repositoryId == repositoryContext.repository.id /* not strict equal, data client IDs are strings vs GitHub responses use numbers */ ||
approval.organizationName && approval.organizationName.toLowerCase() === repositoryContext.repository.organization.name.toLowerCase()) {
basicRepository.approvalLicense = approval.initialLicense;
basicRepository.approvalJustification = approval.releaseReviewJustification;
if (approval.releaseReviewType && releaseTypeMapping) {
const approvalTypes = Object.getOwnPropertyNames(releaseTypeMapping);
for (let j = 0; j < approvalTypes.length; j++) {
const id = approvalTypes[j];
const title = releaseTypeMapping[id];
if (approval.projectType === id) {
basicRepository.approvalTypeId = approval.projectType; // ?
// Hard-coded specific to show justification text or approval links
if ((id === 'NewReleaseReview' || id === 'ExistingReleaseReview') && approval.releaseReviewUrl) {