From 44980f7f0a09576507195fa1de561634af18080e Mon Sep 17 00:00:00 2001 From: slugb0t Date: Thu, 10 Oct 2024 19:26:46 -0700 Subject: [PATCH 01/27] test --- bot/utils/tools/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/utils/tools/index.js b/bot/utils/tools/index.js index 72592412..bc41a823 100644 --- a/bot/utils/tools/index.js +++ b/bot/utils/tools/index.js @@ -309,7 +309,7 @@ export async function isRepoEmpty(context, owner, repoName) { } } -/** +/** * * * Verify the installation and analytics collections * @param {object} context - GitHub payload context * @param {object} repository - The repository object metadata From 018b2556a51742d4ea4fab73bf692a9c173a01a8 Mon Sep 17 00:00:00 2001 From: slugb0t Date: Fri, 11 Oct 2024 11:01:20 -0700 Subject: [PATCH 02/27] feat: :sparkles: update status on zenodo workflow error --- bot/index.js | 8 ++++++++ ui/components.d.ts | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/bot/index.js b/bot/index.js index 4f88e2f9..7784c367 100644 --- a/bot/index.js +++ b/bot/index.js @@ -892,6 +892,14 @@ export default async (app, { getRouter }) => { } catch (error) { // Update the issue with the new body await createIssue(context, owner, repository, ISSUE_TITLE, quickTemplate); + await db.zenodoDeposition.update({ + data: { + status: "error", + }, + where: { + repository_id: repository.id, + } + }); consola.error(`Error publishing to Zenodo: ${error}`); } diff --git a/ui/components.d.ts b/ui/components.d.ts index d981901c..76417937 100644 --- a/ui/components.d.ts +++ b/ui/components.d.ts @@ -8,7 +8,27 @@ export {} declare module 'vue' { export interface GlobalComponents { NAlert: typeof import('naive-ui')['NAlert'] + NAvatar: typeof import('naive-ui')['NAvatar'] + NBadge: typeof import('naive-ui')['NBadge'] + NBreadcrumb: typeof import('naive-ui')['NBreadcrumb'] + NBreadcrumbItem: typeof import('naive-ui')['NBreadcrumbItem'] + NButton: typeof import('naive-ui')['NButton'] + NCard: typeof import('naive-ui')['NCard'] + NCheckbox: typeof import('naive-ui')['NCheckbox'] + NCollapse: typeof import('naive-ui')['NCollapse'] + NCollapseItem: typeof import('naive-ui')['NCollapseItem'] + NDivider: typeof import('naive-ui')['NDivider'] + NDropdown: typeof import('naive-ui')['NDropdown'] NFlex: typeof import('naive-ui')['NFlex'] + NForm: typeof import('naive-ui')['NForm'] + NFormItem: typeof import('naive-ui')['NFormItem'] + NInput: typeof import('naive-ui')['NInput'] + NRadio: typeof import('naive-ui')['NRadio'] + NRadioButton: typeof import('naive-ui')['NRadioButton'] + NRadioGroup: typeof import('naive-ui')['NRadioGroup'] + NSelect: typeof import('naive-ui')['NSelect'] + NTag: typeof import('naive-ui')['NTag'] + NTooltip: typeof import('naive-ui')['NTooltip'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] } From 0d92eb83a9070b0ac0b2373cb089f560512f8a8d Mon Sep 17 00:00:00 2001 From: slugb0t Date: Fri, 11 Oct 2024 12:22:21 -0700 Subject: [PATCH 03/27] feat: :sparkles: progress updates on zenodo release to github issue --- bot/archival/index.js | 2 +- bot/cwl/index.js | 7 ++-- bot/index.js | 77 ++++++++++++++++++------------------- bot/license/index.js | 1 - bot/metadata/index.js | 2 +- bot/utils/renderer/index.js | 1 - ui/components.d.ts | 3 -- 7 files changed, 43 insertions(+), 50 deletions(-) diff --git a/bot/archival/index.js b/bot/archival/index.js index 23411cca..8c73acbf 100644 --- a/bot/archival/index.js +++ b/bot/archival/index.js @@ -175,7 +175,7 @@ export async function getZenodoDepositionInfo( } // Create a new version of an existing Zenodo deposition - consola.info(`Creating a new version of Zenodo deposition ${depositionId}...`); + // consola.info(`Creating a new version of Zenodo deposition ${depositionId}...`); const responseText = await createNewVersionOfDeposition(zenodoToken, depositionId); const latestDraftLink = responseText.links.latest_draft; diff --git a/bot/cwl/index.js b/bot/cwl/index.js index f6bb24bf..64493575 100644 --- a/bot/cwl/index.js +++ b/bot/cwl/index.js @@ -119,7 +119,6 @@ export async function applyCWLTemplate( const identifier = createId(); const overallSection = `\n\n## Language Specific Standards\n\nTo make your software FAIR is it important to follow language specific standards and best practices. Codefair will check below that your code complies with applicable standards,`; let url = `${CODEFAIR_DOMAIN}/view/cwl-validation/${identifier}`; - consola.warn(subjects.cwl) // Delete file entries from db if they were removed from the repository if (subjects.cwl.removed_files.length > 0) { @@ -148,7 +147,6 @@ export async function applyCWLTemplate( } // New/Modified CWL files were found, begin validation workflow - consola.start("Validating new/modified CWL files for", repository.name); const cwlFiles = []; let validOverall = true; let tableContent = ""; @@ -158,13 +156,14 @@ export async function applyCWLTemplate( repository_id: repository.id, }, }); - + if (subjects.cwl.files.length === 0) { consola.warn( `No new/modified CWL files found in the repository, ${repository.name}`, ); } - + + consola.start("Validating CWL files for", repository.name); // Validate each CWL file from list for (const file of subjects.cwl.files) { const fileSplit = file.name.split("."); diff --git a/bot/index.js b/bot/index.js index 7784c367..be9920e2 100644 --- a/bot/index.js +++ b/bot/index.js @@ -25,7 +25,7 @@ checkEnvVariable("CODEFAIR_APP_DOMAIN"); const CODEFAIR_DOMAIN = process.env.CODEFAIR_APP_DOMAIN; const ISSUE_TITLE = `FAIR Compliance Dashboard`; const CLOSED_ISSUE_BODY = `Codefair has been disabled for this repository. If you would like to re-enable it, please reopen this issue.`; -const { ZENODO_ENDPOINT, ZENODO_API_ENDPOINT } = process.env; +const { ZENODO_ENDPOINT, ZENODO_API_ENDPOINT, GITHUB_APP_NAME } = process.env; /** * This is the main entrypoint to your Probot app @@ -271,12 +271,6 @@ export default async (app, { getRouter }) => { ); if (installation?.action_count > 0) { - consola.warn( - "Action limit count down:", - installation.action_count, - "for", - repository.name, - ); const result = await db.installation.update({ data: { action_count: { @@ -298,8 +292,7 @@ export default async (app, { getRouter }) => { return; } - if (installation?.action_count === 0) { - consola.warn("Removing action limit for", repository.name); + if (installation?.action_count === 1) { db.installation.update({ data: { action_count: 0, @@ -317,12 +310,11 @@ export default async (app, { getRouter }) => { // Check if the author of the commit is the bot const commitAuthor = context.payload.head_commit.author; - if (commitAuthor && commitAuthor.username === "codefair-test[bot]") { + if (commitAuthor?.name === `${GITHUB_APP_NAME}[bot]`) { const commitMessages = ["chore: 📝 Update CITATION.cff with Zenodo identifier", "chore: 📝 Update codemeta.json with Zenodo identifier"] // consola.info("Commit made by codefair-test, checking commit message..."); - if (latestCommitInfo.latest_commit_message.includes(commitMessages[0]) || latestCommitInfo.latest_commit_message.includes(commitMessages[1])) { - // consola.info("Skipping validation as per commit message."); - return; + if (latestCommitInfo.latest_commit_message === commitMessages[0] || latestCommitInfo.latest_commit_message === commitMessages[1]) { + return; } } @@ -558,8 +550,9 @@ export default async (app, { getRouter }) => { const issueTitle = context.payload.issue.title; const { repository } = context.payload; const owner = context.payload.repository.owner.login; + const potentialBot = context.payload.sender.login; - if (!issueTitle === ISSUE_TITLE) { + if (!issueTitle === ISSUE_TITLE && potentialBot === `${GITHUB_APP_NAME}[bot]`) { return; } @@ -719,7 +712,20 @@ export default async (app, { getRouter }) => { if (issueBody.includes("/); + if (!match) { + throw new Error("Zenodo publish information not found in issue body."); + } + const [depositionId, releaseId, tagVersion, userWhoSubmitted] = match[1].trim().split(/\s+/); + // consola.info("Deposition ID:", depositionId); + // consola.info("Release ID:", releaseId); + // consola.info("Tag Version:", tagVersion); + // consola.info("User Who Submitted:", userWhoSubmitted); try { // 1. Get the metadata from the repository const citationCff = await getCitationContent(context, owner, repository); @@ -738,19 +744,6 @@ export default async (app, { getRouter }) => { throw new Error("Error validating the codemeta:", error); } - // Gather the information for the Zenodo deposition provided in the issue body - const match = issueBody.match(//); - if (!match) { - throw new Error("Zenodo publish information not found in issue body."); - } - - const [depositionId, releaseId, tagVersion, userWhoSubmitted] = match[1].trim().split(/\s+/); - - consola.info("Deposition ID:", depositionId); - consola.info("Release ID:", releaseId); - consola.info("Tag Version:", tagVersion); - consola.info("User Who Submitted:", userWhoSubmitted); - // Fetch the Zenodo token from the database const deposition = await db.zenodoToken.findFirst({ where: { @@ -782,11 +775,16 @@ export default async (app, { getRouter }) => { // 3. Create the Zenodo record or get the existing one let zenodoDepositionInfo = await getZenodoDepositionInfo(depositionId, zenodoToken); - + // 4. Set the bucket URL and DOI const newDepositionId = zenodoDepositionInfo.id; const bucket_url = zenodoDepositionInfo.links.bucket; const zenodoDoi = zenodoDepositionInfo.metadata.prereserve_doi.doi; + + // Update the GitHub issue with a status report + const tempString = `${issueBodyNoArchiveSection}\n\n## FAIR Software Release 🔄\n***${tagVersion}*** of your software is being released on GitHub and archived on Zenodo. A draft deposition was created and will be adding the necessary files and metadata.`; + const finalTempString = await applyLastModifiedTemplate(tempString); + await createIssue(context, owner, repository, ISSUE_TITLE, finalTempString); // 5. Update the CITATION.cff and codemeta.json files with the DOI await updateMetadataIdentifier(context, owner, repository, zenodoDoi, tagVersion); @@ -831,6 +829,11 @@ export default async (app, { getRouter }) => { await uploadReleaseAssetsToZenodo(zenodoToken, draftRelease.data.assets, repositoryArchive, owner, context, bucket_url, repository, tagVersion); + // Update the GitHub issue with a status report + const afterUploadString = `${issueBodyNoArchiveSection}\n\n## FAIR Software Release 🔄\n***${tagVersion}*** of your software is being released on GitHub and archived on Zenodo. All assets from the GitHub repository's draft release have been successfully uploaded to the Zenodo deposition draft.`; + const finalUploadString = await applyLastModifiedTemplate(afterUploadString); + await createIssue(context, owner, repository, ISSUE_TITLE, finalUploadString); + // 8. Publish the Zenodo deposition consola.start("Publishing the Zenodo deposition...", newDepositionId); const publishDeposition = await fetch( @@ -862,14 +865,9 @@ export default async (app, { getRouter }) => { consola.success("Updated release to not be a draft!"); // 9. Append to the issueBody that the deposition has been published - // First remove everything after the ## Fair Software Release - // consola.warn(issueBody); - const updatedIssueBody = quickTemplate.substring(0, issueBody.indexOf("## FAIR Software Release")); - const badgeURL = `${CODEFAIR_DOMAIN}/dashboard/${owner}/${repository.name}/release/zenodo`; - const releaseBadge = `[![Create Release](https://img.shields.io/badge/Create_Release-00bcd4.svg)](${badgeURL})` const badge = `[![DOI](https://img.shields.io/badge/DOI-${zenodoDoi}-blue)](${ZENODO_ENDPOINT}/records/${newDepositionId})`; - const newIssueBody = `${updatedIssueBody}\n\n## FAIR Software Release ✔️\n***${tagVersion}*** of your software was successfully released on GitHub and archived on Zenodo. You can view the Zenodo archive by clicking the button below:\n\n${badge}\n\nReady to create your next FAIR release? Click the button below:\n\n${releaseBadge}`; - const finalTemplate = await applyLastModifiedTemplate(newIssueBody); + const issueBodyArchiveSection = `${issueBodyNoArchiveSection}\n\n## FAIR Software Release ✔️\n***${tagVersion}*** of your software was successfully released on GitHub and archived on Zenodo. You can view the Zenodo archive by clicking the button below:\n\n${badge}\n\nReady to create your next FAIR release? Click the button below:\n\n${releaseBadge}`; + const finalTemplate = await applyLastModifiedTemplate(issueBodyArchiveSection); // Update the issue with the new body await createIssue(context, owner, repository, ISSUE_TITLE, finalTemplate); @@ -891,7 +889,10 @@ export default async (app, { getRouter }) => { consola.success("Updated the Zenodo deposition in the database!"); } catch (error) { // Update the issue with the new body - await createIssue(context, owner, repository, ISSUE_TITLE, quickTemplate); + // Update the GitHub issue with a status report + const afterUploadString = `${issueBodyNoArchiveSection}\n\n## FAIR Software Release ❌\n***${tagVersion}*** of your software was not successfully released on GitHub and archived on Zenodo. There was an error during the publication process. Please try again later or reach out to the Codefair team for additional help.`; + const finalUploadString = await applyLastModifiedTemplate(afterUploadString); + await createIssue(context, owner, repository, ISSUE_TITLE, finalUploadString); await db.zenodoDeposition.update({ data: { status: "error", @@ -902,8 +903,6 @@ export default async (app, { getRouter }) => { }); consola.error(`Error publishing to Zenodo: ${error}`); } - - } }); diff --git a/bot/license/index.js b/bot/license/index.js index 2ea566f3..7cc4ffd0 100644 --- a/bot/license/index.js +++ b/bot/license/index.js @@ -16,7 +16,6 @@ const CODEFAIR_DOMAIN = process.env.CODEFAIR_APP_DOMAIN; * @returns {boolean} - Returns true if a license is found in the repository, false otherwise */ export async function checkForLicense(context, owner, repo) { - consola.info("Checking for license..."); try { await context.octokit.rest.licenses.getForRepo({ owner, diff --git a/bot/metadata/index.js b/bot/metadata/index.js index 67217a16..e0106083 100644 --- a/bot/metadata/index.js +++ b/bot/metadata/index.js @@ -520,7 +520,7 @@ export async function applyMetadataTemplate( }); if (license?.license_id) { - + metadata.license = `https://spdx.org/licenses/${license.license_id}`; } // License, codemeta.json and CITATION.cff files were found diff --git a/bot/utils/renderer/index.js b/bot/utils/renderer/index.js index 4e8a0baf..29052dc4 100644 --- a/bot/utils/renderer/index.js +++ b/bot/utils/renderer/index.js @@ -30,7 +30,6 @@ export async function renderIssues( subjects, prInfo = { title: "", link: "" }, ) { - consola.info("Is repository empty?", emptyRepo); if (emptyRepo) { consola.success( "Applying empty repo template for repository:", diff --git a/ui/components.d.ts b/ui/components.d.ts index 76417937..58afd572 100644 --- a/ui/components.d.ts +++ b/ui/components.d.ts @@ -18,7 +18,6 @@ declare module 'vue' { NCollapse: typeof import('naive-ui')['NCollapse'] NCollapseItem: typeof import('naive-ui')['NCollapseItem'] NDivider: typeof import('naive-ui')['NDivider'] - NDropdown: typeof import('naive-ui')['NDropdown'] NFlex: typeof import('naive-ui')['NFlex'] NForm: typeof import('naive-ui')['NForm'] NFormItem: typeof import('naive-ui')['NFormItem'] @@ -27,8 +26,6 @@ declare module 'vue' { NRadioButton: typeof import('naive-ui')['NRadioButton'] NRadioGroup: typeof import('naive-ui')['NRadioGroup'] NSelect: typeof import('naive-ui')['NSelect'] - NTag: typeof import('naive-ui')['NTag'] - NTooltip: typeof import('naive-ui')['NTooltip'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] } From d93d321f9ee627931a58ecedec342eaa73017b37 Mon Sep 17 00:00:00 2001 From: Sanjay Soundarajan Date: Fri, 11 Oct 2024 12:50:01 -0700 Subject: [PATCH 04/27] feat: add support for zenodo progress (#80) --- ui/components.d.ts | 1 + ui/pages/dashboard/[owner]/[repo]/index.vue | 57 +++++++++- .../[owner]/[repo]/release/zenodo.vue | 107 +++++++++++++++++- ui/prisma/schema.prisma | 2 +- ui/server/api/[owner]/[repo]/dashboard.get.ts | 10 ++ .../[repo]/release/zenodo/index.get.ts | 4 +- .../[repo]/release/zenodo/index.post.ts | 11 ++ .../[repo]/release/zenodo/status.get.ts | 32 ++++++ 8 files changed, 210 insertions(+), 14 deletions(-) create mode 100644 ui/server/api/[owner]/[repo]/release/zenodo/status.get.ts diff --git a/ui/components.d.ts b/ui/components.d.ts index 58afd572..e7617c99 100644 --- a/ui/components.d.ts +++ b/ui/components.d.ts @@ -22,6 +22,7 @@ declare module 'vue' { NForm: typeof import('naive-ui')['NForm'] NFormItem: typeof import('naive-ui')['NFormItem'] NInput: typeof import('naive-ui')['NInput'] + NModal: typeof import('naive-ui')['NModal'] NRadio: typeof import('naive-ui')['NRadio'] NRadioButton: typeof import('naive-ui')['NRadioButton'] NRadioGroup: typeof import('naive-ui')['NRadioGroup'] diff --git a/ui/pages/dashboard/[owner]/[repo]/index.vue b/ui/pages/dashboard/[owner]/[repo]/index.vue index 135e93c6..b0800b45 100644 --- a/ui/pages/dashboard/[owner]/[repo]/index.vue +++ b/ui/pages/dashboard/[owner]/[repo]/index.vue @@ -223,15 +223,20 @@ const handleSettingsSelect = (key: any) => { Contains a valid license - - @@ -438,6 +443,46 @@ const handleSettingsSelect = (key: any) => { + +