diff --git a/.github/workflows/addRefinedIssuesToBacklog.yml b/.github/workflows/addRefinedIssuesToBacklog.yml new file mode 100644 index 0000000..7f33bde --- /dev/null +++ b/.github/workflows/addRefinedIssuesToBacklog.yml @@ -0,0 +1,184 @@ +name: Move Issues with Status "Done" from Refinement to Backlog Project + +jobs: + move-done-issues: + runs-on: ubuntu-latest + steps: + + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Move Issues from Refinement Board (in Status "Done") to Project Backlog (with Status "ToDo") + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GH_READ_TOKEN }} + script: | + const org = context.repo.owner; + const projectP1 = ${{ env.PROJECT_REFINEMENT_ID }}; // Project ID for "Refinement Board" + const projectP2 = ${{ env.PROJECT_BACKLOG_ID }}; // Project ID for "Backlog Project" + const statusFieldIdP1 =${{ env.ISSUE_REFINEMENT_STATUS_ID }}; // Issue Status field ID for Refinement Board + const statusFieldIdP2 = ${{ env.ISSUE_BACKLOG_STATUS_ID }}; // Issue Status field ID for Project Backlog + const doneStatus = ${{ env.ISSUE_REFINEMENT_DONE_STATUS_ID }}; // "Done" Status Option ID of Refinement Board + const todoStatus = ${{ env.ISSUE_BACKLOG_TODO_STATUS_ID }}; // "ToDo Status Option ID of Backlog Project + + // Fetch all issues in Refinement Board + const query = ` + query { + node(id: "${projectP1}") { + ... on ProjectV2 { + items(first: 100) { + nodes { + id + content { + __typename + ... on Issue { + id + number + title + } + } + fieldValues(first: 10) { + nodes { + __typename + ... on ProjectV2ItemFieldSingleSelectValue { + field { + __typename + ... on ProjectV2SingleSelectField { + id + name + options { + id + name + } + } + } + optionId + } + } + } + } + } + } + } + } + `; + + const result = await github.graphql(query); + const items = result.node.items.nodes; + const doneItems = []; + + // log the items structure for debugging + // console.log("items structure: ", JSON.stringify(items, null, 2)); + + // log the field values structure for debugging + items.forEach(item => { + // console.log(JSON.stringify(item.fieldValues.nodes, null, 2)); + item.fieldValues.nodes.forEach(field => { + if (field.__typename === "ProjectV2ItemFieldSingleSelectValue") { + if (field.optionId === doneStatus) { + console.log(`Issue ${item.content.title} (#${item.content.number}) is in "Done" status -> should be added to Backlog.`); + doneItems.push(item); + } + } + }); + }); + + if (doneItems.length === 0) { + console.log("No issues in 'Done' status, nothing to do."); + return; + } + + // Main Loop over all items in "Done" status + // 1. Adds issue to Project Backlog + // 2. Sets status to "To Do" in Project Backlog + // 3. Removes issue from Refinement Board + for (const item of doneItems) { + if (!item.content || !item.content.number) continue; + + let issueNumber = item.content.number; + let issueTitle = item.content.title; + console.log(`**** Start Processing Issue ${issueTitle} (#${issueNumber}) ****`); + + // 1. Add issue to Project Backlog + const addToProjectMutation = ` + mutation { + addProjectV2ItemById(input: { + projectId: "${projectP2}", + contentId: "${item.content.id}" + }) { + item { + id + } + } + } + `; + + let addToProjectResult; + try { + addToProjectResult = await github.graphql(addToProjectMutation); + + if (addToProjectResult && addToProjectResult.addProjectV2ItemById.item.id) { + console.log(`Issue ${issueTitle} (#${issueNumber}) successfully added to backlog project.`); + } else { + console.error("Failed to add issue ${issueTitle} (#${issueNumber}) to backlog project."); + } + } catch (error) { + console.error("Error in add to Backlog Project GraphQL mutation:", error); + } + + let newProjectItemId = addToProjectResult.addProjectV2ItemById.item.id; + + // 2. Set status to "To Do" in Backlog Project + const updateStatusMutation = ` + mutation { + updateProjectV2ItemFieldValue(input: { + projectId: "${projectP2}", + itemId: "${newProjectItemId}", + fieldId: "${statusFieldIdP2}", + value: { singleSelectOptionId: "${todoStatus}" } + }) { + projectV2Item { + id + } + } + } + `; + + let updateStatusResult; + try { + updateStatusResult = await github.graphql(updateStatusMutation); + if (updateStatusResult && updateStatusResult.updateProjectV2ItemFieldValue.projectV2Item.id) { + console.log(`Changed Status to TODO for Issue ${issueTitle} (#${issueNumber}).`); + } else { + console.error("Failed to change status to TODO for Issue ${issueTitle} (#${issueNumber})."); + } + } catch (error) { + console.error("Error in Change Status GraphQL mutation:", error); + } + + // 3. Remove issue from Refinement Board + const deleteMutation = ` + mutation { + deleteProjectV2Item(input: { + projectId: "${projectP1}", + itemId: "${item.id}" + }) { + deletedItemId + } + } + `; + + let deleteResult; + try { + deleteResult = await github.graphql(deleteMutation); + if (deleteResult && deleteResult.deleteProjectV2Item.deletedItemId) { + console.log(`Issue ${issueTitle} (#${issueNumber}) successfully removed from refinement project.`); + } else { + console.error("Failed to remove issue ${issueTitle} (#${issueNumber}) from refinement project."); + } + } catch (error) { + console.error("Error in delete from refinement project GraphQL mutation:", error); + } + + console.log(`**** Finished processing Issue ${issueTitle} (#${issueNumber}) ****`); + } \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/profile/README.md b/profile/README.md index c387176..874d79f 100755 --- a/profile/README.md +++ b/profile/README.md @@ -1,10 +1,23 @@ -### Run better together with Open Source - -- [Open Source @ SAP](https://opensource.sap.com) -- [SAP Open Source Manifesto](https://github.com/SAP/open-source-manifesto) -- [Open Source Community @ SAP](https://pages.community.sap.com/topics/open-source) -- [Podcast series "The Open Source Way"](https://podcast.opensap.info/open-source-way/) -- [Webinar series "SAP Open Source"](https://webinars.sap.com/ospo-webinar-series/en/home) -- [Blog posts](https://community.sap.com/t5/open-source-blogs/bg-p/open-sourceblog-board) -- [Jobs](https://jobs.sap.com/search/?q=%22open+source%22) -- [External Report 2023](https://dam.sap.com/mac/app/e/pdf/preview/embed/NG3Cg8G?ltr=a&rc=10&includeRelatedAssets=true) +# Welcome to the Open Managed Control Plane (openMCP) Project on GitHub + +:wave: Welcome to the official GitHub presence of openMCP. We are part of [ApeiroRA](https://apeirora.eu/content/projects/) which is an Important Project of Common European Interest - Next Generation Cloud Infrastructures and Services (IPCEI-CIS). + +## :globe_with_meridians: ApeiroRA? + +ApeiroRA is a reference blueprint for an open, flexible, secure, and compliant next-generation cloud-edge continuum and therefore a key contribution to IPCEI-CIS. At a high level, the projects of ApeiroRA allow users to provider-agnostically fetch, request and consume services, and for service providers to describe, offer and provision their services. + +By being open source, ApeiroRA provides a cross-border spillover effect, solidifying the foundation and future of the project. + +Learn more about ApeiroRA by checking out the official website at [https://apeirora.eu/](https://apeirora.eu/). + +## :handshake: openMCP and ApeiroRA + +The Open Managed Control Plane (openMCP) enables extensible Infrastructure- and Configuration-as-Data capabilities as a Service. Based on the Kubernetes Resource Model, all resources in the cloud-edge continuum with ApeiroRA are accessible and managed via a declarative API and corresponding controllers and operators. Together with the controller which understand OCM and declarative deployment orchestrators, consumers can subscribe to a product release-train of software producers and implement an automated, GitOps-driven deployment workflow at the edges. + +## :busts_in_silhouette: Get Involved + +We welcome contributions of all kinds, from code to documentation, testing, and design. If you're interested in getting involved, check out our [open issues](https://github.com/issues?q=is%3Aopen+is%3Aissue+org%3Aopenmcp-project+archived%3Afalse+). + +## 🌈 Code of Conduct + +To facilitate a nice environment for all, check out [our Code of Conduct](https://github.com/openmcp-project/.github/blob/main/CODE_OF_CONDUCT.md).