From fe189900819a269f9b2d8413c4ca6855cf3bf515 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:12:08 +0000 Subject: [PATCH 1/9] Add community blog structure and contribution guardrails --- .github/CODEOWNERS | 2 + .github/PULL_REQUEST_TEMPLATE/blog_post.md | 14 +++ .github/workflows/blog-post-validation.yml | 106 +++++++++++++++++++++ CONTRIBUTING.md | 22 +++++ _sidebar.md | 1 + blog/README.md | 16 ++++ blog/_template.md | 13 +++ blog/posts/2026-06-24-community-welcome.md | 16 ++++ 8 files changed, 190 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/PULL_REQUEST_TEMPLATE/blog_post.md create mode 100644 .github/workflows/blog-post-validation.yml create mode 100644 blog/README.md create mode 100644 blog/_template.md create mode 100644 blog/posts/2026-06-24-community-welcome.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..4d202f911 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +/blog/** @MichaelCade + diff --git a/.github/PULL_REQUEST_TEMPLATE/blog_post.md b/.github/PULL_REQUEST_TEMPLATE/blog_post.md new file mode 100644 index 000000000..0253ab2d7 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/blog_post.md @@ -0,0 +1,14 @@ +## Blog Post Submission + +### Summary + +Describe your post in 2-4 sentences. + +### Checklist + +- [ ] I added my post under `blog/posts/` with filename format `YYYY-MM-DD-short-title.md` +- [ ] I used the metadata schema from `blog/_template.md` (`title`, `author`, `date`, `tags`, `summary`) +- [ ] My post is original and relevant to the 90DaysOfDevOps community topics +- [ ] I verified local markdown links and image paths +- [ ] I have read and followed `/home/runner/work/90DaysOfDevOps/90DaysOfDevOps/CONTRIBUTING.md` + diff --git a/.github/workflows/blog-post-validation.yml b/.github/workflows/blog-post-validation.yml new file mode 100644 index 000000000..7c9877e85 --- /dev/null +++ b/.github/workflows/blog-post-validation.yml @@ -0,0 +1,106 @@ +name: Blog Post Validation + +on: + pull_request: + paths: + - "blog/posts/*.md" + - "blog/_template.md" + +jobs: + validate-blog-posts: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Collect changed blog posts + env: + BASE_SHA: ${{ github.event.pull_request.base.sha }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: | + git diff --name-only "$BASE_SHA" "$HEAD_SHA" -- 'blog/posts/*.md' > changed_blog_posts.txt + echo "Changed posts:" + cat changed_blog_posts.txt || true + + - name: Validate metadata and local links + run: | + python - <<'PY' + from pathlib import Path + from datetime import datetime + import re + import sys + + changed_file_list = Path("changed_blog_posts.txt") + changed_files = [] + if changed_file_list.exists(): + changed_files = [line.strip() for line in changed_file_list.read_text(encoding="utf-8").splitlines() if line.strip()] + + if not changed_files: + print("No changed blog post files detected.") + raise SystemExit(0) + + required_fields = ["title", "author", "date", "tags", "summary"] + all_errors = [] + + for rel_path in changed_files: + path = Path(rel_path) + if not path.exists(): + continue + + text = path.read_text(encoding="utf-8") + lines = text.splitlines() + errors = [] + + if not lines or lines[0].strip() != "---": + errors.append("Missing YAML front matter opening delimiter '---'.") + else: + end_idx = None + for idx in range(1, len(lines)): + if lines[idx].strip() == "---": + end_idx = idx + break + if end_idx is None: + errors.append("Missing YAML front matter closing delimiter '---'.") + front_matter_lines = [] + else: + front_matter_lines = lines[1:end_idx] + + if end_idx is not None: + front_matter_text = "\n".join(front_matter_lines) + for field in required_fields: + if not re.search(rf"(?m)^{field}\s*:", front_matter_text): + errors.append(f"Missing required metadata field: {field}") + + date_match = re.search(r'(?m)^date\s*:\s*"?(.*?)"?\s*$', front_matter_text) + if date_match: + date_value = date_match.group(1).strip() + try: + datetime.strptime(date_value, "%Y-%m-%d") + except ValueError: + errors.append("Invalid date format. Expected YYYY-MM-DD.") + + for link in re.findall(r"\[[^\]]+\]\(([^)]+)\)", text): + target = link.strip() + if not target or target.startswith(("http://", "https://", "mailto:", "#")): + continue + target = target.split("#", 1)[0].split("?", 1)[0] + if not target: + continue + resolved = (path.parent / target).resolve() + if not resolved.exists(): + errors.append(f"Broken local link: {link}") + + if errors: + all_errors.append(f"{rel_path}:") + all_errors.extend([f" - {err}" for err in errors]) + + if all_errors: + print("Validation failed:\n") + print("\n".join(all_errors)) + sys.exit(1) + + print("All changed blog posts passed metadata and local link validation.") + PY + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0ff2f255c..c0b00ea2b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -38,6 +38,28 @@ To send us a pull request, please: 6. Send us a pull request, answering any default questions in the pull request. 7. Pay attention to any automated failures reported in the pull request, and stay involved in the conversation. +## Submit a Blog Post + +We welcome community blog contributions for publishing on the GitHub Pages site. + +Please follow these requirements: + +1. Create your post file in `/blog/posts/` using this filename format: `YYYY-MM-DD-short-title.md`. +2. Start from `/blog/_template.md` and include all required metadata fields: + - `title` + - `author` + - `date` (YYYY-MM-DD) + - `tags` (list) + - `summary` +3. Keep content original, respectful, and relevant to DevOps, DevSecOps, platform engineering, cloud, automation, SRE, or adjacent community learning topics. +4. Add local images under a suitable folder in the repository and use relative links. +5. Open a pull request with the **Blog Post Submission** template and complete every checklist item. + +Review expectations: + +- Blog pull requests require maintainer review. +- Posts may be edited or declined if they do not meet topic, originality, quality, or community standards. + GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). diff --git a/_sidebar.md b/_sidebar.md index 52cf4dfa6..d721337f7 100644 --- a/_sidebar.md +++ b/_sidebar.md @@ -1,6 +1,7 @@ - 90DaysOfDevOps - [2022 Version](2022.md) - [2023 Version](2023.md) + - [Community Blog](blog/README.md) - Info - [Resources](Resources.md) diff --git a/blog/README.md b/blog/README.md new file mode 100644 index 000000000..a9b2e8e4c --- /dev/null +++ b/blog/README.md @@ -0,0 +1,16 @@ +# Community Blog + +Welcome to the 90DaysOfDevOps community blog. + +This section is for community-submitted posts merged through pull requests. + +## Blog Posts + +- [Welcome to the Community Blog](posts/2026-06-24-community-welcome.md) + +## Submit a Blog Post + +1. Copy the template from [`blog/_template.md`](./_template.md). +2. Create a new file in `blog/posts/` using `YYYY-MM-DD-short-title.md`. +3. Open a pull request using the **Blog Post Submission** template. + diff --git a/blog/_template.md b/blog/_template.md new file mode 100644 index 000000000..61d11c286 --- /dev/null +++ b/blog/_template.md @@ -0,0 +1,13 @@ +--- +title: "Your Post Title" +author: "Your Name" +date: "YYYY-MM-DD" +tags: + - devops +summary: "One or two sentence summary of your post." +--- + +# Your Post Title + +Write your post here. + diff --git a/blog/posts/2026-06-24-community-welcome.md b/blog/posts/2026-06-24-community-welcome.md new file mode 100644 index 000000000..26bf4382b --- /dev/null +++ b/blog/posts/2026-06-24-community-welcome.md @@ -0,0 +1,16 @@ +--- +title: "Welcome to the 90DaysOfDevOps Community Blog" +author: "90DaysOfDevOps Maintainers" +date: "2026-06-24" +tags: + - community + - devops +summary: "An introduction to community blog submissions in this repository." +--- + +# Welcome to the 90DaysOfDevOps Community Blog + +This new blog section allows community members to submit practical DevOps write-ups through pull requests. + +Use the template in `blog/_template.md`, add your post to `blog/posts/`, and open a pull request for review. + From e2e58ac072413d0df152dbad9c5ad968490aa273 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:13:26 +0000 Subject: [PATCH 2/9] Fix blog PR template path and workflow token permissions --- .github/PULL_REQUEST_TEMPLATE/blog_post.md | 3 +-- .github/workflows/blog-post-validation.yml | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE/blog_post.md b/.github/PULL_REQUEST_TEMPLATE/blog_post.md index 0253ab2d7..987e4e6d7 100644 --- a/.github/PULL_REQUEST_TEMPLATE/blog_post.md +++ b/.github/PULL_REQUEST_TEMPLATE/blog_post.md @@ -10,5 +10,4 @@ Describe your post in 2-4 sentences. - [ ] I used the metadata schema from `blog/_template.md` (`title`, `author`, `date`, `tags`, `summary`) - [ ] My post is original and relevant to the 90DaysOfDevOps community topics - [ ] I verified local markdown links and image paths -- [ ] I have read and followed `/home/runner/work/90DaysOfDevOps/90DaysOfDevOps/CONTRIBUTING.md` - +- [ ] I have read and followed `CONTRIBUTING.md` diff --git a/.github/workflows/blog-post-validation.yml b/.github/workflows/blog-post-validation.yml index 7c9877e85..f57697fdc 100644 --- a/.github/workflows/blog-post-validation.yml +++ b/.github/workflows/blog-post-validation.yml @@ -6,6 +6,9 @@ on: - "blog/posts/*.md" - "blog/_template.md" +permissions: + contents: read + jobs: validate-blog-posts: runs-on: ubuntu-latest @@ -103,4 +106,3 @@ jobs: print("All changed blog posts passed metadata and local link validation.") PY - From df9d55bded497e13f9a8996542edb5c22d8ff27b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:14:13 +0000 Subject: [PATCH 3/9] Harden blog date validation against future dates --- .github/workflows/blog-post-validation.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/blog-post-validation.yml b/.github/workflows/blog-post-validation.yml index f57697fdc..890b859a1 100644 --- a/.github/workflows/blog-post-validation.yml +++ b/.github/workflows/blog-post-validation.yml @@ -80,7 +80,9 @@ jobs: if date_match: date_value = date_match.group(1).strip() try: - datetime.strptime(date_value, "%Y-%m-%d") + post_date = datetime.strptime(date_value, "%Y-%m-%d").date() + if post_date > datetime.now().date(): + errors.append("Date cannot be in the future.") except ValueError: errors.append("Invalid date format. Expected YYYY-MM-DD.") From 65f68ef47f4344b866e4ea15a782d95ac65a4688 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:37:09 +0000 Subject: [PATCH 4/9] fix: deploy Docsify site to gh-pages branch on push to main --- .github/workflows/deploy-pages.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/deploy-pages.yml diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml new file mode 100644 index 000000000..a1a84a82e --- /dev/null +++ b/.github/workflows/deploy-pages.yml @@ -0,0 +1,28 @@ +name: Deploy GitHub Pages + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: ${{ github.repository }}-pages + cancel-in-progress: false + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Deploy to gh-pages branch + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: . + publish_branch: gh-pages + exclude_assets: '.github,.git,template_repository' From c8d2956bc2f3c5aff60b68d40184fa310d54d687 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:40:56 +0000 Subject: [PATCH 5/9] Initial plan From 2c34c7d0a54fcf1e29812d941702f6b002106078 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:44:36 +0000 Subject: [PATCH 6/9] fix: remove .git from exclude_assets to fix deploy workflow --- .github/workflows/deploy-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml index a1a84a82e..9ec294d63 100644 --- a/.github/workflows/deploy-pages.yml +++ b/.github/workflows/deploy-pages.yml @@ -25,4 +25,4 @@ jobs: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: . publish_branch: gh-pages - exclude_assets: '.github,.git,template_repository' + exclude_assets: '.github,template_repository' From 84ecea85e0b68cfdbee52e77d6b2eda7f0a68d35 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Jun 2026 15:02:15 +0000 Subject: [PATCH 7/9] fix: correct blog post link path and revert theme to vue.css --- blog/README.md | 2 +- index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/blog/README.md b/blog/README.md index a9b2e8e4c..ec83f7287 100644 --- a/blog/README.md +++ b/blog/README.md @@ -6,7 +6,7 @@ This section is for community-submitted posts merged through pull requests. ## Blog Posts -- [Welcome to the Community Blog](posts/2026-06-24-community-welcome.md) +- [Welcome to the Community Blog](/blog/posts/2026-06-24-community-welcome.md) ## Submit a Blog Post diff --git a/index.html b/index.html index 9e79507c0..02bdb31ea 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,7 @@ - + From ecf9bac2fa2dcfaa0485baa6935ab40d83d82d9d Mon Sep 17 00:00:00 2001 From: Michael Cade Date: Wed, 24 Jun 2026 16:17:59 +0100 Subject: [PATCH 8/9] Add 2024 Version link to sidebar --- _sidebar.md | 1 + 1 file changed, 1 insertion(+) diff --git a/_sidebar.md b/_sidebar.md index d721337f7..248f3f294 100644 --- a/_sidebar.md +++ b/_sidebar.md @@ -1,6 +1,7 @@ - 90DaysOfDevOps - [2022 Version](2022.md) - [2023 Version](2023.md) + - [2024 Version](2024.md) - [Community Blog](blog/README.md) - Info From 2941b895eaac2056ec9431a21f3d09a60a3752f8 Mon Sep 17 00:00:00 2001 From: Michael Cade Date: Wed, 24 Jun 2026 16:28:22 +0100 Subject: [PATCH 9/9] Remove Discord invite link Removed Discord invite link from README. --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 6bd307c20..7fbc14f6e 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,6 @@ The project is not a sponsored operation by any vendors and everything is access [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/N4N33YRCS) -[![Discord Invite Link](https://dcbadge.vercel.app/api/server/vqwPrNQsyK)](https://discord.gg/vqwPrNQsyK) - ![GitHub Repo Stars](https://img.shields.io/github/stars/michaelcade/90daysofdevops?style=social?)