From 2b3da0779d195a277ab6709f25a17c43e7630db1 Mon Sep 17 00:00:00 2001 From: Katharina Sick Date: Thu, 19 Mar 2026 14:36:48 +0100 Subject: [PATCH] chore: add contribution templates & automations Signed-off-by: Katharina Sick --- .github/ISSUE_TEMPLATE/bug.yml | 38 ++++++++++ .github/ISSUE_TEMPLATE/config.yml | 6 ++ .github/ISSUE_TEMPLATE/improvement.yml | 32 +++++++++ .github/pull_request_template.md | 56 +++++++++++++++ .github/workflows/idea-tracking-issue.yml | 61 ++++++++++++++++ .github/workflows/walkthrough-issues.yml | 82 ++++++++++++++++++++++ docs/contributing/adventure-ideas.md | 2 +- docs/contributing/adventures.md | 6 +- docs/contributing/solution-walkthroughs.md | 2 +- 9 files changed, 281 insertions(+), 4 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/improvement.yml create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/idea-tracking-issue.yml create mode 100644 .github/workflows/walkthrough-issues.yml diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 00000000..2250fdee --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,38 @@ +name: Bug Report +description: Something is broken +labels: ["bug"] +body: + - type: textarea + id: what + attributes: + label: What's broken? + description: Describe what's not working. + placeholder: "e.g. The smoke test script fails with a permission error even after completing the challenge." + validations: + required: true + - type: textarea + id: reproduce + attributes: + label: Steps to reproduce + placeholder: | + 1. Open Codespace for Adventure 01 β€” Beginner + 2. Run `adventures/01-echoes-lost-in-orbit/beginner/smoke-test.sh` + 3. See error: ... + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected behavior + description: What should happen instead? + placeholder: "e.g. The script should pass and print a success message." + validations: + required: true + - type: textarea + id: where + attributes: + label: Where? + description: Link to the relevant page, file, or adventure level. + placeholder: "e.g. https://dynatrace-oss.github.io/open-ecosystem-challenges/01-echoes-lost-in-orbit/beginner" + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..828e604a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,6 @@ +blank_issues_enabled: false +contact_links: + - name: Questions & Discussions + url: https://community.open-ecosystem.com/c/challenges + about: Ask questions and discuss challenges in the Open Ecosystem community. + diff --git a/.github/ISSUE_TEMPLATE/improvement.yml b/.github/ISSUE_TEMPLATE/improvement.yml new file mode 100644 index 00000000..a0188b90 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/improvement.yml @@ -0,0 +1,32 @@ +name: Improvement +description: Suggest an improvement or enhancement +labels: ["enhancement"] +body: + - type: textarea + id: what + attributes: + label: What could be improved? + description: Describe the improvement you have in mind. + placeholder: "e.g. The beginner guide for Adventure 01 doesn't explain what Kustomize overlays are, which makes the first objective confusing." + validations: + required: true + - type: textarea + id: where + attributes: + label: Where? + description: Link to the relevant page, file, or adventure level. + placeholder: "e.g. https://dynatrace-oss.github.io/open-ecosystem-challenges/01-echoes-lost-in-orbit/beginner" + validations: + required: true + - type: textarea + id: why + attributes: + label: Why would this help? + description: What problem does this solve or what value does it add? + placeholder: "e.g. Participants without a Kubernetes background get stuck here and there's no hint pointing them in the right direction." + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: Any other approaches you thought about? + placeholder: "e.g. Linking to the Kustomize docs would also work, but a short inline explanation would be less disruptive." diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..4535d196 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,56 @@ +## What does this PR do? + + + +Closes # + +## Type of PR + +- [ ] πŸ’‘ Adventure Idea +- [ ] πŸ—ΊοΈ New Adventure Level +- [ ] πŸ“– Solution Walkthrough +- [ ] πŸ› Bug fix / πŸ“ Documentation improvement / Other + +--- + +### πŸ’‘ Adventure Idea + + + +- [ ] Idea file is placed in `ideas/` (not `ideas/.implemented/`) + +--- + +### πŸ—ΊοΈ New Adventure Level + + + + +- [ ] Devcontainer tested from scratch in a new Codespace +- [ ] `verify.sh` passes when the challenge is solved +- [ ] `verify.sh` fails with helpful error messages when not solved +- [ ] Docs complete: story, objectives, hints, no spoilers +- [ ] All links in docs work +- [ ] Idea file moved to `ideas/.implemented/` (first level PR only) +- [ ] Tracking issue linked above (`Part of #` for earlier levels, `Closes #` for the last one) + +--- + +### πŸ“– Solution Walkthrough + + + +- [ ] External link (blog post, video, etc.) β€” linked from the adventure's solutions page +- [ ] In-repo markdown (`adventures/XX-.../docs/solutions/level.md`) +- [ ] The challenge deadline has passed +- [ ] Walkthrough explains *why* things work, not just what to do + +--- + +### πŸ“ Other + + + +- [ ] Commits are focused and minimal +- [ ] Documentation updated if needed + diff --git a/.github/workflows/idea-tracking-issue.yml b/.github/workflows/idea-tracking-issue.yml new file mode 100644 index 00000000..85a3c68e --- /dev/null +++ b/.github/workflows/idea-tracking-issue.yml @@ -0,0 +1,61 @@ +name: Create Adventure Idea Tracking Issue + +on: + pull_request: + types: [closed] + +jobs: + create-tracking-issue: + if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'adventure idea') + runs-on: ubuntu-latest + steps: + - name: Create tracking issue + uses: actions/github-script@v8 + with: + script: | + const pr = context.payload.pull_request; + + const { data: files } = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pr.number, + }); + + // Only proceed if a file was *added* to ideas/ (not modified or deleted) + const ideaFile = files.find(f => + f.status === 'added' && + f.filename.startsWith('ideas/') && + !f.filename.startsWith('ideas/.implemented/') && + f.filename.endsWith('.md') + ); + if (!ideaFile) { + console.log('No new idea file added β€” skipping.'); + return; + } + + // Extract adventure name from PR title: "Adventure Idea: Name" -> "Name" + const titleMatch = pr.title.match(/^Adventure Idea:\s*(.+)$/i); + const adventureName = titleMatch ? titleMatch[1].trim() : pr.title; + const fileUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/${ideaFile.filename}`; + + await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: `Build Adventure: ${adventureName}`, + labels: ['adventure idea', 'help wanted'], + body: [ + `## ${adventureName}`, + '', + 'An adventure idea has been approved and is ready to be built! πŸŽ‰', + '', + `**Idea:** [\`${ideaFile.filename}\`](${fileUrl})`, + `**Approved in:** ${pr.html_url}`, + '', + '## Want to build it?', + '', + 'Comment on this issue to claim it, then follow the [Building Adventures](https://dynatrace-oss.github.io/open-ecosystem-challenges/contributing/adventures/) guide.', + '', + '**Each level should be a separate PR.** Reference this issue with `Part of #` in earlier PRs and `Closes #` in the final one.', + ].join('\n'), + }); + diff --git a/.github/workflows/walkthrough-issues.yml b/.github/workflows/walkthrough-issues.yml new file mode 100644 index 00000000..d18e5887 --- /dev/null +++ b/.github/workflows/walkthrough-issues.yml @@ -0,0 +1,82 @@ +name: Create Solution Walkthrough Issues + +on: + pull_request: + types: [closed] + +jobs: + create-walkthrough-issues: + if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'new level') + runs-on: ubuntu-latest + steps: + - name: Create walkthrough issues + uses: actions/github-script@v8 + with: + script: | + const pr = context.payload.pull_request; + const LEVELS = { beginner: '🟒', intermediate: '🟑', expert: 'πŸ”΄' }; + const LEVEL_ORDER = ['beginner', 'intermediate', 'expert']; + + const { data: files } = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pr.number, + }); + + // Only create issues for newly *added* verify.sh files (= new levels being released) + const newLevels = new Map(); + for (const file of files) { + const match = file.filename.match( + /^adventures\/((?!planned)[^/]+)\/(beginner|intermediate|expert)\/verify\.sh$/ + ); + if (match && file.status === 'added') { + const [, adventure, level] = match; + if (!newLevels.has(adventure)) newLevels.set(adventure, new Set()); + newLevels.get(adventure).add(level); + } + } + + if (newLevels.size === 0) { + console.log('No new verify.sh files β€” skipping.'); + return; + } + + for (const [adventure, levels] of newLevels) { + // "03-the-ai-observatory" -> "03: The AI Observatory" + const nameMatch = adventure.match(/^(\d+)-(.+)$/); + const adventureName = nameMatch + ? `${nameMatch[1]}: ${nameMatch[2].replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase())}` + : adventure; + + for (const level of LEVEL_ORDER.filter(l => levels.has(l))) { + const emoji = LEVELS[level]; + const levelName = level.charAt(0).toUpperCase() + level.slice(1); + + await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: `Solution Walkthrough: ${adventureName} β€” ${emoji} ${levelName}`, + labels: ['solution walkthrough'], + body: [ + `## ${adventureName} β€” ${emoji} ${levelName}`, + '', + `Write a solution walkthrough for the **${levelName}** level of **${adventureName}**.`, + '', + '> ⚠️ **Walkthroughs are only accepted after the challenge deadline has passed.**', + '', + '## How to contribute', + '', + 'Comment on this issue to claim it, then follow the [Solution Walkthroughs](https://dynatrace-oss.github.io/open-ecosystem-challenges/contributing/solution-walkthroughs/) guide.', + '', + 'A walkthrough can be:', + "- **External content** β€” a blog post, video, or any public resource. Link to it from the adventure's solutions page.", + `- **In-repo** β€” a markdown file in \`adventures/${adventure}/docs/solutions/${level}.md\``, + '', + "The most useful walkthroughs explain *why* something was broken and how you'd reason your way to the solution.", + '', + `**Adventure added in:** ${pr.html_url}`, + ].join('\n'), + }); + } + } + diff --git a/docs/contributing/adventure-ideas.md b/docs/contributing/adventure-ideas.md index 1b8b70f6..357fa9db 100644 --- a/docs/contributing/adventure-ideas.md +++ b/docs/contributing/adventure-ideas.md @@ -59,7 +59,7 @@ Adventure 01 is a useful reference: Beginner introduces Argo CD ApplicationSets 1. **Create a new file** in `ideas/` named `your-adventure-name.md` 2. **Use the template** below to describe your idea -3. **Open a pull request** with the title `Adventure Idea: Your Adventure Name` +3. **[Open a pull request](https://github.com/dynatrace-oss/open-ecosystem-challenges/compare)** with the title `Adventure Idea: Your Adventure Name` No issue required. Submit your idea directly as a PR. diff --git a/docs/contributing/adventures.md b/docs/contributing/adventures.md index c35cf0c6..4a15b47e 100644 --- a/docs/contributing/adventures.md +++ b/docs/contributing/adventures.md @@ -22,6 +22,8 @@ An adventure consists of: Use `00` as the adventure number during development. When your adventure is scheduled for release, maintainers will assign the final number and move it out of `planned/`. +If `adventures/planned/` doesn't exist yet, create it. + ``` adventures/planned/00-adventure-name/ β”œβ”€β”€ README.md # Brief intro + link to docs @@ -169,7 +171,7 @@ Before submitting: ## Tips -- **Open a draft PR early.** Get feedback on structure before completing everything. -- **Start with one level.** Get it working before building all three. +- **[Open a draft PR early.](https://github.com/dynatrace-oss/open-ecosystem-challenges/compare)** Get feedback on structure before completing everything. +- **Ship one level at a time.** Each level gets its own PR β€” start with one, get it working, then build the next. Use `Part of #` on all but the last PR, and `Closes #` on the final one so the tracking issue closes automatically. - **Test on slow connections.** Codespace startup time matters. - **Write clear error messages.** Help participants understand what went wrong without giving away the solution. \ No newline at end of file diff --git a/docs/contributing/solution-walkthroughs.md b/docs/contributing/solution-walkthroughs.md index f84ceb7f..59bc6b3a 100644 --- a/docs/contributing/solution-walkthroughs.md +++ b/docs/contributing/solution-walkthroughs.md @@ -6,7 +6,7 @@ Solution walkthroughs help participants who get stuck and serve as learning reso ## How to Contribute -Browse [walkthrough issues](https://github.com/dynatrace-oss/open-ecosystem-challenges/issues?q=is%3Aissue+is%3Aopen+label%3A%22solution+walkthrough%22), comment to claim a level, and submit your walkthrough as a PR. Walkthroughs can take any form: +Browse [walkthrough issues](https://github.com/dynatrace-oss/open-ecosystem-challenges/issues?q=is%3Aissue+is%3Aopen+label%3A%22solution+walkthrough%22), comment to claim a level, and [submit your walkthrough as a PR](https://github.com/dynatrace-oss/open-ecosystem-challenges/compare). Walkthroughs can take any form: - **External content** β€” a blog post, video, or any public resource. Just link to it from the adventure's solutions page. - **In-repo** β€” a markdown file in `adventures/XX-adventure-name/docs/solutions/`.