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..987e4e6d7 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/blog_post.md @@ -0,0 +1,13 @@ +## 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 `CONTRIBUTING.md` diff --git a/.github/workflows/blog-post-validation.yml b/.github/workflows/blog-post-validation.yml new file mode 100644 index 000000000..890b859a1 --- /dev/null +++ b/.github/workflows/blog-post-validation.yml @@ -0,0 +1,110 @@ +name: Blog Post Validation + +on: + pull_request: + paths: + - "blog/posts/*.md" + - "blog/_template.md" + +permissions: + contents: read + +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: + 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.") + + 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/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml new file mode 100644 index 000000000..9ec294d63 --- /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,template_repository' 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/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?) diff --git a/_sidebar.md b/_sidebar.md index 52cf4dfa6..248f3f294 100644 --- a/_sidebar.md +++ b/_sidebar.md @@ -1,6 +1,8 @@ - 90DaysOfDevOps - [2022 Version](2022.md) - [2023 Version](2023.md) + - [2024 Version](2024.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..ec83f7287 --- /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](/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. + diff --git a/index.html b/index.html index 9e79507c0..02bdb31ea 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,7 @@ - +