From e0fae09be2330f86917a404a63f10c91d86339ed Mon Sep 17 00:00:00 2001 From: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> Date: Tue, 9 Dec 2025 12:28:42 -0800 Subject: [PATCH 01/14] feat: add initial templates and sync workflow Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> --- .github/CODEOWNERS | 1 + .github/dependabot.yml | 19 ++ .github/ghalint.yml | 7 + .github/sync.yml | 34 +++ .github/workflows/__dependency-review.yml | 32 +++ .github/workflows/sync.yml | 62 ++++++ sync-templates/.editorconfig | 36 ++++ sync-templates/.gitattributes | 29 +++ sync-templates/LICENSE | 204 ++++++++++++++++++ workflow-templates/README.md | 4 + .../dependency-review.properties.json | 9 + workflow-templates/dependency-review.yml | 16 ++ 12 files changed, 453 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/dependabot.yml create mode 100644 .github/ghalint.yml create mode 100644 .github/sync.yml create mode 100644 .github/workflows/__dependency-review.yml create mode 100644 .github/workflows/sync.yml create mode 100644 sync-templates/.editorconfig create mode 100644 sync-templates/.gitattributes create mode 100644 sync-templates/LICENSE create mode 100644 workflow-templates/README.md create mode 100644 workflow-templates/dependency-review.properties.json create mode 100644 workflow-templates/dependency-review.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..12fe39a --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @radius-project/on-call diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..38281c1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,19 @@ +# yaml-language-server: $schema=https://www.schemastore.org/dependabot-2.0.json +# See GitHub's documentation for more information on this file: +# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference +--- +version: 2 + +updates: + - package-ecosystem: github-actions + directories: + - / + - workflow-templates + schedule: + interval: weekly + commit-message: + prefix: ci + include: scope + groups: + all: + patterns: ["*"] diff --git a/.github/ghalint.yml b/.github/ghalint.yml new file mode 100644 index 0000000..1f33931 --- /dev/null +++ b/.github/ghalint.yml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/suzuki-shunsuke/ghalint/main/json-schema/ghalint.json +--- +excludes: + - policy_name: github_app_should_limit_repositories + workflow_file_path: .github/workflows/sync.yml + job_name: sync + step_id: get-token diff --git a/.github/sync.yml b/.github/sync.yml new file mode 100644 index 0000000..905db37 --- /dev/null +++ b/.github/sync.yml @@ -0,0 +1,34 @@ +# docs: https://github.com/PaddleHQ/repo-file-sync-action?tab=readme-ov-file#advanced-sync-config +# nunjucks template: https://mozilla.github.io/nunjucks/templating.html +--- +group: + # source: https://github.com/orgs/radius-project/repositories?q=archived%3Afalse+sort%3Aname-asc + repos: | + radius-project/.github + radius-project/bicep-types-aws + radius-project/blog + radius-project/community + radius-project/dashboard + radius-project/design-notes + radius-project/docs@edge + radius-project/lab + radius-project/radius + radius-project/recipes + radius-project/resource-types-contrib + radius-project/roadmap + radius-project/samples@edge + radius-project/terraform-private-modules + radius-project/website + + files: + - source: sync-templates/LICENSE + dest: LICENSE + + - source: sync-templates/.gitattributes + dest: .gitattributes + + - source: sync-templates/.editorconfig + dest: .editorconfig + + - source: workflow-templates/dependency-review.yml + dest: .github/workflows/dependency-review.yml diff --git a/.github/workflows/__dependency-review.yml b/.github/workflows/__dependency-review.yml new file mode 100644 index 0000000..170983f --- /dev/null +++ b/.github/workflows/__dependency-review.yml @@ -0,0 +1,32 @@ +# yaml-language-server: $schema=https://www.schemastore.org/github-workflow.json +# docs: +# - https://github.com/actions/dependency-review-action +# - https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/configuring-the-dependency-review-action +--- +name: __dependency-review + +on: + workflow_call: + +permissions: {} + +jobs: + dependency-review: + runs-on: ubuntu-24.04 + timeout-minutes: 5 + permissions: + contents: read + pull-requests: write + checks: write + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + persist-credentials: false + + - name: Run Dependency Review + uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2 + with: + comment-summary-in-pr: always + retry-on-snapshot-warnings: true + warn-on-openssf-scorecard-level: 4 diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml new file mode 100644 index 0000000..45c4a62 --- /dev/null +++ b/.github/workflows/sync.yml @@ -0,0 +1,62 @@ +# yaml-language-server: $schema=https://www.schemastore.org/github-workflow.json +--- +name: Sync + +on: + push: + branches: + - main + paths: + - .github/workflows/sync.yml + - .github/sync.yml + - sync-templates/** + - workflow-templates/*.yaml + - workflow-templates/*.yml + +permissions: {} + +concurrency: + group: ${{ format('{0}-{1}-{2}-{3}-{4}', github.workflow, github.event_name, github.ref, github.base_ref, github.head_ref) }} + cancel-in-progress: true + +jobs: + sync: + name: Sync + runs-on: ubuntu-24.04 + timeout-minutes: 15 + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + persist-credentials: false + + - name: Get App Token + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 + id: get-token + with: + app-id: ${{ secrets.SYNC_BOT_APP_ID }} + private-key: ${{ secrets.SYNC_BOT_PRIVATE_KEY }} + owner: ${{ github.repository_owner }} + permission-metadata: read + permission-contents: write + permission-pull-requests: write + permission-workflows: write + + - name: Get bot details + id: bot-details + uses: raven-actions/bot-details@ee8966a9ff6e7e42cbfc4a56b4ddb60a9d1b40a6 # v1.2.0 + with: + bot-slug-name: ${{ steps.get-token.outputs.app-slug }} + set-env: false + + - name: Run Repo File Sync + uses: PaddleHQ/repo-file-sync-action@fb024b6e51a36213d16cc4b2c3b51c73b2b5ca70 # v1.26.13 + with: + GH_INSTALLATION_TOKEN: ${{ steps.get-token.outputs.token }} + CONFIG_PATH: ./.github/sync.yml + COMMIT_PREFIX: "chore:" + BRANCH_PREFIX: repo-sync + GIT_EMAIL: ${{ steps.bot-details.outputs.email }} + GIT_USERNAME: ${{ steps.bot-details.outputs.name }} diff --git a/sync-templates/.editorconfig b/sync-templates/.editorconfig new file mode 100644 index 0000000..8a4fd1a --- /dev/null +++ b/sync-templates/.editorconfig @@ -0,0 +1,36 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 2 + +[*.{go,mod}] +indent_style = tab + +[*.{tsv}] +indent_style = tab + +[*.md] +indent_size = unset + +[*.py] +indent_size = 4 + +[*.ps1] +indent_size = 4 + +[*.{cmd,bat}] +end_of_line = crlf + +[Makefile] +indent_style = tab + +[**/node_modules/**] +ignore = true + +[**/.venv/**] +ignore = true diff --git a/sync-templates/.gitattributes b/sync-templates/.gitattributes new file mode 100644 index 0000000..c52f020 --- /dev/null +++ b/sync-templates/.gitattributes @@ -0,0 +1,29 @@ +# Force the following filetypes to have unix eols, so Windows does not break them +* text eol=lf + +# Declare files that will always have CRLF line endings on checkout. +*.{cmd,[cC][mM][dD]} text eol=crlf +*.{bat,[bB][aA][tT]} text eol=crlf + +# Common files +*.pdf binary + +# Image files +*.gif binary +*.tif binary +*.ico binary +*.jpg binary +*.jpeg binary +*.png binary + +# Microsoft Office documents +*.pptx binary +*.potx binary +*.docx binary +*.dotx binary +*.vsdx binary + +# Lock files +package-lock.json linguist-generated=true +pnpm-lock.yaml linguist-generated=true +yarn.lock linguist-generated=true diff --git a/sync-templates/LICENSE b/sync-templates/LICENSE new file mode 100644 index 0000000..585a73f --- /dev/null +++ b/sync-templates/LICENSE @@ -0,0 +1,204 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 The Radius Authors. + + and others that have contributed code to the public domain. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/workflow-templates/README.md b/workflow-templates/README.md new file mode 100644 index 0000000..8734636 --- /dev/null +++ b/workflow-templates/README.md @@ -0,0 +1,4 @@ +# Workflow Templates + +- [Creating workflow templates for your organization](https://docs.github.com/en/actions/how-tos/reuse-automations/create-workflow-templates) +- [Metadata file requirements](https://docs.github.com/en/actions/reference/workflows-and-actions/reusing-workflow-configurations#metadata-file-requirements) diff --git a/workflow-templates/dependency-review.properties.json b/workflow-templates/dependency-review.properties.json new file mode 100644 index 0000000..22fc8f7 --- /dev/null +++ b/workflow-templates/dependency-review.properties.json @@ -0,0 +1,9 @@ +{ + "name": "Dependency Review", + "description": "Dependency Review workflow template.", + "iconName": "package-dependencies", + "categories": [ + "dependency-management" + ], + "filePatterns": [] +} diff --git a/workflow-templates/dependency-review.yml b/workflow-templates/dependency-review.yml new file mode 100644 index 0000000..1b98639 --- /dev/null +++ b/workflow-templates/dependency-review.yml @@ -0,0 +1,16 @@ +# yaml-language-server: $schema=https://www.schemastore.org/github-workflow.json +--- +name: Dependency Review + +on: + pull_request: + +permissions: {} + +jobs: + dependency-review: + uses: radius-project/.github/.github/workflows/__dependency-review.yml@main + permissions: + contents: read + pull-requests: write + checks: write From ac767095f3885cd1e22ef4a774fa18de201bf511 Mon Sep 17 00:00:00 2001 From: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> Date: Tue, 9 Dec 2025 12:51:53 -0800 Subject: [PATCH 02/14] docs(eng): add SYNC Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> --- eng/SYNC.md | 380 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100644 eng/SYNC.md diff --git a/eng/SYNC.md b/eng/SYNC.md new file mode 100644 index 0000000..65865d0 --- /dev/null +++ b/eng/SYNC.md @@ -0,0 +1,380 @@ +# Repository Files Sync + +This document describes the centralized file synchronization used across the `radius-project` organization to maintain consistency and governance standards across all repositories. + +## Table of Contents + +- [Table of Contents](#table-of-contents) +- [Overview](#overview) + - [Key Benefits](#key-benefits) +- [Architecture](#architecture) +- [Directory Structure](#directory-structure) +- [How Sync Works](#how-sync-works) + - [Trigger Conditions](#trigger-conditions) + - [Sync Process](#sync-process) + - [Authentication](#authentication) +- [Configuration Files](#configuration-files) + - [`.github/sync.yml` - Sync Configuration](#githubsyncyml---sync-configuration) +- [Sync Templates](#sync-templates) +- [Workflow Templates](#workflow-templates) + - [1. GitHub Workflow Templates (UI)](#1-github-workflow-templates-ui) + - [2. Synced Workflows](#2-synced-workflows) + - [Example Templates](#example-templates) +- [Reusable Workflows](#reusable-workflows) + - [Naming Convention: `__` Prefix](#naming-convention-__-prefix) + - [Examples](#examples) + - [Workflow Relationship Diagram](#workflow-relationship-diagram) + - [Usage Pattern](#usage-pattern) +- [Adding New Files to Sync](#adding-new-files-to-sync) + - [Step 1: Add the Source File](#step-1-add-the-source-file) + - [Step 2: Update Sync Configuration](#step-2-update-sync-configuration) + - [Step 3: Commit and Push](#step-3-commit-and-push) +- [Target Repositories](#target-repositories) +- [Troubleshooting](#troubleshooting) + - [Sync Not Triggering](#sync-not-triggering) + - [PRs Not Created](#prs-not-created) + - [File Not Appearing in Target Repo](#file-not-appearing-in-target-repo) + - [Merge Conflicts](#merge-conflicts) +- [References](#references) + +--- + +## Overview + +The `.github` repository serves as the **Single Source of Truth** (SSoT) for organization-wide configurations, templates, and policies. It uses an automated synchronization to distribute common files (such as licenses, linter configs, workflows, etc) to all repositories in the `radius-project` organization. + +### Key Benefits + +- 🔄 **Consistency**: Ensures all repositories follow the same standards +- 🛡️ **Governance**: Centralized control over critical files like LICENSE +- ⚡ **Automation**: Changes automatically propagate via Pull Requests +- 📝 **Audit Trail**: All changes are tracked through Git history and PRs + +--- + +## Architecture + +```mermaid +flowchart TB + subgraph central[".github Repository - Central Configuration Hub"] + subgraph sources["Source Directories"] + sync_templates["sync-templates/\n(static files)"] + workflow_templates["workflow-templates/\n(workflow files)"] + end + + sync_config[".github/sync.yml\nSync Configuration"] + sync_workflow[".github/workflows/sync.yml\nSync Workflow"] + + sync_templates --> sync_config + workflow_templates --> sync_config + sync_config --> sync_workflow + end + + sync_workflow -->|"Triggered on push to main\n(when sync-related files change)"| sync_action + + sync_action["PaddleHQ/repo-file-sync-action\nCreates PRs in target repositories"] + + sync_action --> repo_a["org/repo-a"] + sync_action --> repo_b["org/repo-b"] + sync_action --> repo_c["org/repo-c"] + sync_action --> repo_n["... (N repos)"] +``` + +--- + +## Directory Structure + +```text +.github/ +├── .github/ # GitHub-specific configurations for THIS repo +│ ├── sync.yml # ⚙️ SYNC CONFIGURATION FILE +│ └── workflows/ +│ ├── sync.yml # ⚙️ SYNC WORKFLOW +│ └── __.yml # Reusable workflows (prefixed with __) +│ +├── sync-templates/ # 📁 Static files and nunjucks templates to sync +│ ├── # Files synced as-is (no transformation) +│ └── .njk # Nunjucks templates (rendered before sync) +│ +├── workflow-templates/ # 📁 GitHub Actions workflow templates +│ ├── README.md # Documentation for workflow templates +│ ├── .yml # Workflow template file +│ └── .properties.json # Template metadata +│ +└── eng/ # 📁 Engineering documentation + └── SYNC.md # This file +``` + +--- + +## How Sync Works + +### Trigger Conditions + +The sync workflow (`.github/workflows/sync.yml`) is triggered when: + +1. Code is pushed to the `main` branch +1. **AND** changes are made to any of these paths: + - `.github/workflows/sync.yml` (the workflow itself) + - `.github/sync.yml` (sync configuration) + - `sync-templates/**` (any file in sync-templates) + - `workflow-templates/*.yaml` or `workflow-templates/*.yml` + +### Sync Process + +1. **Checkout**: The workflow checks out the `.github` repository +1. **Authentication**: Obtains a GitHub App token with permissions for: + - `metadata: read` + - `contents: write` + - `pull-requests: write` + - `workflows: write` +1. **Bot Identity**: Retrieves bot details for commit attribution +1. **File Sync**: Uses [PaddleHQ/repo-file-sync-action](https://github.com/PaddleHQ/repo-file-sync-action) to: + - Read the sync configuration from `.github/sync.yml` + - Create branches (prefixed with `repo-sync`) in target repos + - Copy files from source to destination paths + - Open Pull Requests with commit messages prefixed with `chore:` + +### Authentication + +The sync uses a **GitHub App** for authentication (configured via secrets): + +- `SYNC_BOT_APP_ID`: The GitHub App ID +- `SYNC_BOT_PRIVATE_KEY`: The GitHub App private key + +This approach provides: + +- Fine-grained permissions +- Better audit trails +- No dependency on personal access tokens + +--- + +## Configuration Files + +### `.github/sync.yml` - Sync Configuration + +This is the heart of the sync. It defines: + +- **Target repositories** (in the `repos` section) +- **File mappings** (source → destination) + +```yaml +group: + repos: | + radius-project/.github + radius-project/repo-a + radius-project/repo-b@custom-branch # Can specify different branches + # ... more repos + + files: + - source: sync-templates/LICENSE + dest: LICENSE + + - source: sync-templates/.gitattributes + dest: .gitattributes + + - source: workflow-templates/.yml + dest: .github/workflows/.yml +``` + +**Key Features:** + +- Uses [nunjucks templating](https://mozilla.github.io/nunjucks/templating.html) for advanced configurations +- Supports branch specification with `@branch` syntax +- Supports directory patterns and exclusions + +--- + +## Sync Templates + +The `sync-templates/` directory contains files that are synchronized **as-is** to target repositories. These are static files that should be identical across all repositories in the organization. + +**Common use cases:** + +- License files (e.g., `LICENSE`) +- Editor configuration files (e.g., `.editorconfig`) +- Git configuration files (e.g., `.gitattributes`) +- Code of conduct, contributing guidelines +- Any other file that should be standardized across repositories + +Files placed in this directory are copied directly to the destination path specified in the sync configuration, without any transformation or templating. + +--- + +## Workflow Templates + +Files in `workflow-templates/` serve **two purposes**: + +### 1. GitHub Workflow Templates (UI) + +When developers create new workflows in any organization repository, they see these templates in the GitHub Actions UI. Each template requires: + +- `.yml` - The workflow file +- `.properties.json` - Metadata (name, description, icon, categories) + +**Example properties file:** + +```json +{ + "name": "Example Workflow", + "description": "Description of what this workflow does.", + "iconName": "icon-name", + "categories": ["category-1", "category-2"], + "filePatterns": [] +} +``` + +### 2. Synced Workflows + +The same workflow files are synced to repositories via the sync, ensuring all repos have the workflow automatically. + +### Example Templates + +| Template | Description | +|----------|-------------| +| `dependency-review.yml` | Scans PR dependencies for vulnerabilities | +| `lint.yml` | Runs linting checks on code changes | +| `ci.yml` | Continuous integration workflow | + +--- + +## Reusable Workflows + +### Naming Convention: `__` Prefix + +Files in `.github/workflows/` that are intended to be **reusable workflows** (callable by other repositories) **MUST** be prefixed with double underscores (`__`). + +**Why this convention?** + +- 🔍 **Visual Distinction**: Easily identify which workflows are reusable vs. internal +- 📂 **Sorting**: `__` prefixed files appear at the top of directory listings +- 🔒 **Safety**: Prevents accidental modification of shared workflows +- 📖 **Documentation**: Self-documenting naming convention + +**Naming pattern:** `__.yml` + +### Examples + +| Workflow | Description | +|----------|-------------| +| `__dependency-review.yml` | Runs dependency scanning with standard config | +| `__lint.yml` | Shared linting workflow | +| `__build.yml` | Shared build workflow | + +### Workflow Relationship Diagram + +```mermaid +flowchart LR + subgraph central[".github Repository"] + reusable["__example-workflow.yml\n(Reusable Workflow)"] + template["workflow-templates/\nexample-workflow.yml\n(Template - calls reusable)"] + end + + subgraph target["Target Repository"] + synced[".github/workflows/\nexample-workflow.yml\n(Synced from template)"] + end + + template -->|"Synced via\nrepo-file-sync-action"| synced + synced -->|"uses: org/.github/...\n__example-workflow.yml@main"| reusable +``` + +### Usage Pattern + +Target repositories call reusable workflows instead of duplicating logic: + +```yaml +# In target repository (synced from workflow-templates/) +jobs: + example-job: + uses: radius-project/.github/.github/workflows/__example-workflow.yml@main + permissions: + contents: read + pull-requests: write +``` + +--- + +## Adding New Files to Sync + +### Step 1: Add the Source File + +Place the file in the appropriate directory: + +- **Static files** (LICENSE, configs) → `sync-templates/` +- **Workflows** → `workflow-templates/` + +### Step 2: Update Sync Configuration + +Edit `.github/sync.yml` to add the new file mapping: + +```yaml +files: + # Existing files... + + - source: sync-templates/NEW_FILE + dest: NEW_FILE +``` + +### Step 3: Commit and Push + +Push to `main` branch. The sync workflow will automatically: + +1. Detect the change +1. Create PRs in all target repositories + +--- + +## Target Repositories + +The sync targets repositories defined in `.github/sync.yml`. Example structure: + +| Repository | Branch | Notes | +|------------|--------|-------| +| `radius-project/.github` | main | This repository (self-sync) | +| `radius-project/main-project` | main | Main project repository | +| `radius-project/docs` | **edge** | Custom branch example | +| `radius-project/website` | main | | +| `radius-project/samples` | **edge** | Custom branch example | +| ... | ... | Add all repositories to sync | + +> **Note:** Use `@branch` syntax in `sync.yml` to specify non-default branches (e.g., `radius-project/docs@edge`). + +--- + +## Troubleshooting + +### Sync Not Triggering + +1. Verify you pushed to `main` branch +1. Check that changed files match the path filters in `sync.yml` +1. Review Actions tab for workflow runs + +### PRs Not Created + +1. Check GitHub App permissions +1. Verify secrets `SYNC_BOT_APP_ID` and `SYNC_BOT_PRIVATE_KEY` are set +1. Review sync workflow logs for errors + +### File Not Appearing in Target Repo + +1. Verify file mapping in `.github/sync.yml` +1. Check if the file already exists (sync may skip or require manual merge) +1. Look for open PRs from the sync bot + +### Merge Conflicts + +The sync action creates PRs, not direct commits. If conflicts occur: + +1. Review the PR in the target repository +1. Resolve conflicts manually +1. Merge the PR + +--- + +## References + +- [PaddleHQ/repo-file-sync-action](https://github.com/PaddleHQ/repo-file-sync-action) - The sync action used +- [Creating workflow templates](https://docs.github.com/en/actions/how-tos/reuse-automations/create-workflow-templates) - GitHub docs +- [Reusable workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows) - GitHub docs +- [GitHub Apps](https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/about-creating-github-apps) - Authentication method From a9b344c16941684c2c6aba1c493dc1ed5f15f27b Mon Sep 17 00:00:00 2001 From: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> Date: Tue, 9 Dec 2025 12:53:45 -0800 Subject: [PATCH 03/14] fix: update flowchart formatting in SYNC.md for better readability Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> --- eng/SYNC.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/eng/SYNC.md b/eng/SYNC.md index 65865d0..ccdcada 100644 --- a/eng/SYNC.md +++ b/eng/SYNC.md @@ -58,21 +58,21 @@ The `.github` repository serves as the **Single Source of Truth** (SSoT) for org flowchart TB subgraph central[".github Repository - Central Configuration Hub"] subgraph sources["Source Directories"] - sync_templates["sync-templates/\n(static files)"] - workflow_templates["workflow-templates/\n(workflow files)"] + sync_templates["sync-templates/
(static files)"] + workflow_templates["workflow-templates/
(workflow files)"] end - sync_config[".github/sync.yml\nSync Configuration"] - sync_workflow[".github/workflows/sync.yml\nSync Workflow"] + sync_config[".github/sync.yml
Sync Configuration"] + sync_workflow[".github/workflows/sync.yml
Sync Workflow"] sync_templates --> sync_config workflow_templates --> sync_config sync_config --> sync_workflow end - sync_workflow -->|"Triggered on push to main\n(when sync-related files change)"| sync_action + sync_workflow -->|"Triggered on push to main
(when sync-related files change)"| sync_action - sync_action["PaddleHQ/repo-file-sync-action\nCreates PRs in target repositories"] + sync_action["PaddleHQ/repo-file-sync-action
Creates PRs in target repositories"] sync_action --> repo_a["org/repo-a"] sync_action --> repo_b["org/repo-b"] @@ -267,16 +267,16 @@ Files in `.github/workflows/` that are intended to be **reusable workflows** (ca ```mermaid flowchart LR subgraph central[".github Repository"] - reusable["__example-workflow.yml\n(Reusable Workflow)"] - template["workflow-templates/\nexample-workflow.yml\n(Template - calls reusable)"] + reusable["__example-workflow.yml
(Reusable Workflow)"] + template["workflow-templates/
example-workflow.yml
(Template - calls reusable)"] end subgraph target["Target Repository"] - synced[".github/workflows/\nexample-workflow.yml\n(Synced from template)"] + synced[".github/workflows/
example-workflow.yml
(Synced from template)"] end - template -->|"Synced via\nrepo-file-sync-action"| synced - synced -->|"uses: org/.github/...\n__example-workflow.yml@main"| reusable + template -->|"Synced via
repo-file-sync-action"| synced + synced -->|"uses: org/.github/...
__example-workflow.yml@main"| reusable ``` ### Usage Pattern From 1584b90b105f6fa2e0c1dc42dbb01854f60f6556 Mon Sep 17 00:00:00 2001 From: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> Date: Tue, 9 Dec 2025 14:21:17 -0800 Subject: [PATCH 04/14] fix: update sync workflow secrets in documentation and configuration Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> --- .github/sync.yml | 1 + .github/workflows/sync.yml | 6 +++--- eng/SYNC.md | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/sync.yml b/.github/sync.yml index 905db37..22830ad 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -1,3 +1,4 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/raven-actions/repo-files-sync/main/sync.schema.json # docs: https://github.com/PaddleHQ/repo-file-sync-action?tab=readme-ov-file#advanced-sync-config # nunjucks template: https://mozilla.github.io/nunjucks/templating.html --- diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml index 45c4a62..2c64f0d 100644 --- a/.github/workflows/sync.yml +++ b/.github/workflows/sync.yml @@ -36,8 +36,8 @@ jobs: uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 id: get-token with: - app-id: ${{ secrets.SYNC_BOT_APP_ID }} - private-key: ${{ secrets.SYNC_BOT_PRIVATE_KEY }} + app-id: ${{ secrets.FILES_SYNC_BOT_APP_ID }} + private-key: ${{ secrets.FILES_SYNC_BOT_PRIVATE_KEY }} owner: ${{ github.repository_owner }} permission-metadata: read permission-contents: write @@ -56,7 +56,7 @@ jobs: with: GH_INSTALLATION_TOKEN: ${{ steps.get-token.outputs.token }} CONFIG_PATH: ./.github/sync.yml - COMMIT_PREFIX: "chore:" + COMMIT_PREFIX: "chore(sync):" BRANCH_PREFIX: repo-sync GIT_EMAIL: ${{ steps.bot-details.outputs.email }} GIT_USERNAME: ${{ steps.bot-details.outputs.name }} diff --git a/eng/SYNC.md b/eng/SYNC.md index ccdcada..4920104 100644 --- a/eng/SYNC.md +++ b/eng/SYNC.md @@ -139,8 +139,8 @@ The sync workflow (`.github/workflows/sync.yml`) is triggered when: The sync uses a **GitHub App** for authentication (configured via secrets): -- `SYNC_BOT_APP_ID`: The GitHub App ID -- `SYNC_BOT_PRIVATE_KEY`: The GitHub App private key +- `FILES_SYNC_BOT_APP_ID`: The GitHub App ID +- `FILES_SYNC_BOT_PRIVATE_KEY`: The GitHub App private key This approach provides: @@ -353,7 +353,7 @@ The sync targets repositories defined in `.github/sync.yml`. Example structure: ### PRs Not Created 1. Check GitHub App permissions -1. Verify secrets `SYNC_BOT_APP_ID` and `SYNC_BOT_PRIVATE_KEY` are set +1. Verify secrets `FILES_SYNC_BOT_APP_ID` and `FILES_SYNC_BOT_PRIVATE_KEY` are set 1. Review sync workflow logs for errors ### File Not Appearing in Target Repo From 919511068d8b5478dd42531d20548213c087a31d Mon Sep 17 00:00:00 2001 From: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> Date: Tue, 9 Dec 2025 14:24:55 -0800 Subject: [PATCH 05/14] fix: improve table formatting in SYNC.md for better clarity Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> --- eng/SYNC.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/eng/SYNC.md b/eng/SYNC.md index 4920104..68b3819 100644 --- a/eng/SYNC.md +++ b/eng/SYNC.md @@ -231,11 +231,11 @@ The same workflow files are synced to repositories via the sync, ensuring all re ### Example Templates -| Template | Description | -|----------|-------------| +| Template | Description | +|-------------------------|-------------------------------------------| | `dependency-review.yml` | Scans PR dependencies for vulnerabilities | -| `lint.yml` | Runs linting checks on code changes | -| `ci.yml` | Continuous integration workflow | +| `lint.yml` | Runs linting checks on code changes | +| `ci.yml` | Continuous integration workflow | --- @@ -256,11 +256,11 @@ Files in `.github/workflows/` that are intended to be **reusable workflows** (ca ### Examples -| Workflow | Description | -|----------|-------------| +| Workflow | Description | +|---------------------------|-----------------------------------------------| | `__dependency-review.yml` | Runs dependency scanning with standard config | -| `__lint.yml` | Shared linting workflow | -| `__build.yml` | Shared build workflow | +| `__lint.yml` | Shared linting workflow | +| `__build.yml` | Shared build workflow | ### Workflow Relationship Diagram @@ -329,14 +329,14 @@ Push to `main` branch. The sync workflow will automatically: The sync targets repositories defined in `.github/sync.yml`. Example structure: -| Repository | Branch | Notes | -|------------|--------|-------| -| `radius-project/.github` | main | This repository (self-sync) | -| `radius-project/main-project` | main | Main project repository | -| `radius-project/docs` | **edge** | Custom branch example | -| `radius-project/website` | main | | -| `radius-project/samples` | **edge** | Custom branch example | -| ... | ... | Add all repositories to sync | +| Repository | Branch | Notes | +|-------------------------------|----------|------------------------------| +| `radius-project/.github` | main | This repository (self-sync) | +| `radius-project/main-project` | main | Main project repository | +| `radius-project/docs` | **edge** | Custom branch example | +| `radius-project/website` | main | | +| `radius-project/samples` | **edge** | Custom branch example | +| ... | ... | Add all repositories to sync | > **Note:** Use `@branch` syntax in `sync.yml` to specify non-default branches (e.g., `radius-project/docs@edge`). From fee440ccba3a4031368a9a1bcc74509b211e7400 Mon Sep 17 00:00:00 2001 From: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> Date: Wed, 10 Dec 2025 20:40:42 +0000 Subject: [PATCH 06/14] feat(sync): add CODEOWNERS Signed-off-by: GitHub Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> --- .github/sync.yml | 53 +++++++++--------- sync-templates/.github/CODEOWNERS.njk | 58 ++++++++++++++++++++ sync-templates/{LICENSE => LICENSE.APACHE20} | 0 3 files changed, 86 insertions(+), 25 deletions(-) create mode 100644 sync-templates/.github/CODEOWNERS.njk rename sync-templates/{LICENSE => LICENSE.APACHE20} (100%) diff --git a/.github/sync.yml b/.github/sync.yml index 22830ad..9a5efa3 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -4,32 +4,35 @@ --- group: # source: https://github.com/orgs/radius-project/repositories?q=archived%3Afalse+sort%3Aname-asc - repos: | - radius-project/.github - radius-project/bicep-types-aws - radius-project/blog - radius-project/community - radius-project/dashboard - radius-project/design-notes - radius-project/docs@edge - radius-project/lab - radius-project/radius - radius-project/recipes - radius-project/resource-types-contrib - radius-project/roadmap - radius-project/samples@edge - radius-project/terraform-private-modules - radius-project/website + - repos: | + radius-project/.github + radius-project/bicep-types-aws + radius-project/blog + radius-project/community + radius-project/dashboard + radius-project/design-notes + radius-project/docs@edge + radius-project/lab + radius-project/radius + radius-project/recipes + radius-project/resource-types-contrib + radius-project/roadmap + radius-project/samples@edge + radius-project/terraform-private-modules + radius-project/website + files: + - source: sync-templates/LICENSE.APACHE20 + dest: LICENSE - files: - - source: sync-templates/LICENSE - dest: LICENSE + - source: sync-templates/.gitattributes + dest: .gitattributes - - source: sync-templates/.gitattributes - dest: .gitattributes + - source: sync-templates/.editorconfig + dest: .editorconfig - - source: sync-templates/.editorconfig - dest: .editorconfig + - source: sync-templates/.github/CODEOWNERS.njk + dest: .github/CODEOWNERS + template: true - - source: workflow-templates/dependency-review.yml - dest: .github/workflows/dependency-review.yml + - source: workflow-templates/dependency-review.yml + dest: .github/workflows/dependency-review.yml diff --git a/sync-templates/.github/CODEOWNERS.njk b/sync-templates/.github/CODEOWNERS.njk new file mode 100644 index 0000000..ddb7b2d --- /dev/null +++ b/sync-templates/.github/CODEOWNERS.njk @@ -0,0 +1,58 @@ +{#- Extract repo name from full_name (e.g., "radius-project/radius" → "radius") -#} +{#- Remove leading dot if present (e.g., ".github" → "github") -#} +{%- set repo_name = context.repo.repo | replace(r/^\./, '') -%} +{%- set maintainers = "@radius-project/maintainers-" + repo_name -%} +{%- set approvers = "@radius-project/approvers-" + repo_name -%} +{%- set oncall = "@radius-project/on-call" -%} +# Code Owners for {{ context.repo.full_name }} +# Generated from template - do not edit directly + +# General maintainers and approvers for the entire repository +* {{ maintainers }} {{ approvers }} + +# Dependency files - on-call can also approve these (Dependabot, etc.) + +# Node.js +**/package.json {{ maintainers }} {{ approvers }} {{ oncall }} +**/package-lock.json {{ maintainers }} {{ approvers }} {{ oncall }} +**/pnpm-lock.yaml {{ maintainers }} {{ approvers }} {{ oncall }} +**/yarn.lock {{ maintainers }} {{ approvers }} {{ oncall }} +**/.nvmrc {{ maintainers }} {{ approvers }} {{ oncall }} +**/.npmrc {{ maintainers }} {{ approvers }} {{ oncall }} +**/.node-version {{ maintainers }} {{ approvers }} {{ oncall }} +**/tsconfig.json {{ maintainers }} {{ approvers }} {{ oncall }} + +# Go +**/go.mod {{ maintainers }} {{ approvers }} {{ oncall }} +**/go.sum {{ maintainers }} {{ approvers }} {{ oncall }} +**/go.work {{ maintainers }} {{ approvers }} {{ oncall }} +**/go.work.sum {{ maintainers }} {{ approvers }} {{ oncall }} + +# .NET +**/*.csproj {{ maintainers }} {{ approvers }} {{ oncall }} +**/*.sln {{ maintainers }} {{ approvers }} {{ oncall }} +**/nuget.config {{ maintainers }} {{ approvers }} {{ oncall }} + +# Python +**/requirements.txt {{ maintainers }} {{ approvers }} {{ oncall }} +**/pyproject.toml {{ maintainers }} {{ approvers }} {{ oncall }} +**/uv.lock {{ maintainers }} {{ approvers }} {{ oncall }} +**/poetry.lock {{ maintainers }} {{ approvers }} {{ oncall }} +**/Pipfile {{ maintainers }} {{ approvers }} {{ oncall }} +**/Pipfile.lock {{ maintainers }} {{ approvers }} {{ oncall }} +**/.python-version {{ maintainers }} {{ approvers }} {{ oncall }} + +# Rust +**/Cargo.toml {{ maintainers }} {{ approvers }} {{ oncall }} +**/Cargo.lock {{ maintainers }} {{ approvers }} {{ oncall }} + +# Bicep +**/bicepconfig.json {{ maintainers }} {{ approvers }} {{ oncall }} + +# Container files +**/Dockerfile {{ maintainers }} {{ approvers }} {{ oncall }} +**/.devcontainer/*.json {{ maintainers }} {{ approvers }} {{ oncall }} + +# GitHub workflows +.github/workflows/*.yml {{ maintainers }} {{ approvers }} {{ oncall }} +.github/workflows/*.yaml {{ maintainers }} {{ approvers }} {{ oncall }} diff --git a/sync-templates/LICENSE b/sync-templates/LICENSE.APACHE20 similarity index 100% rename from sync-templates/LICENSE rename to sync-templates/LICENSE.APACHE20 From ce5dd12007fcf56dc3da562dd37f222ade223cb5 Mon Sep 17 00:00:00 2001 From: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> Date: Wed, 10 Dec 2025 20:58:04 +0000 Subject: [PATCH 07/14] feat: update CODEOWNERS to include additional file patterns Signed-off-by: GitHub Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> --- sync-templates/.github/CODEOWNERS.njk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sync-templates/.github/CODEOWNERS.njk b/sync-templates/.github/CODEOWNERS.njk index ddb7b2d..dde3254 100644 --- a/sync-templates/.github/CODEOWNERS.njk +++ b/sync-templates/.github/CODEOWNERS.njk @@ -21,17 +21,21 @@ **/.npmrc {{ maintainers }} {{ approvers }} {{ oncall }} **/.node-version {{ maintainers }} {{ approvers }} {{ oncall }} **/tsconfig.json {{ maintainers }} {{ approvers }} {{ oncall }} +**/tsconfig.*.json {{ maintainers }} {{ approvers }} {{ oncall }} +**/*.tsconfig.json {{ maintainers }} {{ approvers }} {{ oncall }} # Go **/go.mod {{ maintainers }} {{ approvers }} {{ oncall }} **/go.sum {{ maintainers }} {{ approvers }} {{ oncall }} **/go.work {{ maintainers }} {{ approvers }} {{ oncall }} **/go.work.sum {{ maintainers }} {{ approvers }} {{ oncall }} +**/.go-version {{ maintainers }} {{ approvers }} {{ oncall }} # .NET **/*.csproj {{ maintainers }} {{ approvers }} {{ oncall }} **/*.sln {{ maintainers }} {{ approvers }} {{ oncall }} **/nuget.config {{ maintainers }} {{ approvers }} {{ oncall }} +**/global.json {{ maintainers }} {{ approvers }} {{ oncall }} # Python **/requirements.txt {{ maintainers }} {{ approvers }} {{ oncall }} @@ -51,6 +55,7 @@ # Container files **/Dockerfile {{ maintainers }} {{ approvers }} {{ oncall }} +**/*.Dockerfile {{ maintainers }} {{ approvers }} {{ oncall }} **/.devcontainer/*.json {{ maintainers }} {{ approvers }} {{ oncall }} # GitHub workflows From 15456c7beb36b976a7d3b02b86822460e874f5de Mon Sep 17 00:00:00 2001 From: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> Date: Wed, 10 Dec 2025 21:31:57 +0000 Subject: [PATCH 08/14] fix: update CODEOWNERS template to use dynamic prefixes for maintainers and approvers Signed-off-by: GitHub Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> --- .github/sync.yml | 5 ++++- sync-templates/.github/CODEOWNERS.njk | 9 ++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/sync.yml b/.github/sync.yml index 9a5efa3..e42d2a1 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -32,7 +32,10 @@ group: - source: sync-templates/.github/CODEOWNERS.njk dest: .github/CODEOWNERS - template: true + template: + maintainers-prefix: "@radius-project/maintainers-" + approvers-prefix: "@radius-project/approvers-" + oncall: "@radius-project/on-call" - source: workflow-templates/dependency-review.yml dest: .github/workflows/dependency-review.yml diff --git a/sync-templates/.github/CODEOWNERS.njk b/sync-templates/.github/CODEOWNERS.njk index dde3254..f50f37d 100644 --- a/sync-templates/.github/CODEOWNERS.njk +++ b/sync-templates/.github/CODEOWNERS.njk @@ -1,10 +1,9 @@ {#- Extract repo name from full_name (e.g., "radius-project/radius" → "radius") -#} {#- Remove leading dot if present (e.g., ".github" → "github") -#} -{%- set repo_name = context.repo.repo | replace(r/^\./, '') -%} -{%- set maintainers = "@radius-project/maintainers-" + repo_name -%} -{%- set approvers = "@radius-project/approvers-" + repo_name -%} -{%- set oncall = "@radius-project/on-call" -%} -# Code Owners for {{ context.repo.full_name }} +{%- set repo_name = repo.name | replace(r/^\./, '') -%} +{%- set maintainers = maintainers-prefix + repo_name -%} +{%- set approvers = approvers-prefix + repo_name -%} +# Code Owners for {{ repo.full_name }} # Generated from template - do not edit directly # General maintainers and approvers for the entire repository From b9f679869a82522dbb82fe087b1ab81fd814951f Mon Sep 17 00:00:00 2001 From: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> Date: Wed, 10 Dec 2025 21:32:28 +0000 Subject: [PATCH 09/14] fix: correct casing in CODEOWNERS comment for repo.fullName Signed-off-by: GitHub Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> --- sync-templates/.github/CODEOWNERS.njk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync-templates/.github/CODEOWNERS.njk b/sync-templates/.github/CODEOWNERS.njk index f50f37d..f4db6bf 100644 --- a/sync-templates/.github/CODEOWNERS.njk +++ b/sync-templates/.github/CODEOWNERS.njk @@ -3,7 +3,7 @@ {%- set repo_name = repo.name | replace(r/^\./, '') -%} {%- set maintainers = maintainers-prefix + repo_name -%} {%- set approvers = approvers-prefix + repo_name -%} -# Code Owners for {{ repo.full_name }} +# Code Owners for {{ repo.fullName }} # Generated from template - do not edit directly # General maintainers and approvers for the entire repository From 1cd9d26e0496ae047b060826ae9e794279bdc5f0 Mon Sep 17 00:00:00 2001 From: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> Date: Wed, 10 Dec 2025 21:32:51 +0000 Subject: [PATCH 10/14] fix: update comment in CODEOWNERS template to clarify repo name extraction Signed-off-by: GitHub Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> --- sync-templates/.github/CODEOWNERS.njk | 1 - 1 file changed, 1 deletion(-) diff --git a/sync-templates/.github/CODEOWNERS.njk b/sync-templates/.github/CODEOWNERS.njk index f4db6bf..6c1a271 100644 --- a/sync-templates/.github/CODEOWNERS.njk +++ b/sync-templates/.github/CODEOWNERS.njk @@ -1,4 +1,3 @@ -{#- Extract repo name from full_name (e.g., "radius-project/radius" → "radius") -#} {#- Remove leading dot if present (e.g., ".github" → "github") -#} {%- set repo_name = repo.name | replace(r/^\./, '') -%} {%- set maintainers = maintainers-prefix + repo_name -%} From 5cc1f024c1590a4904b55dd27239f3cf3223043f Mon Sep 17 00:00:00 2001 From: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> Date: Wed, 10 Dec 2025 21:34:54 +0000 Subject: [PATCH 11/14] fix: correct comment syntax in CODEOWNERS template Signed-off-by: GitHub Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> --- sync-templates/.github/CODEOWNERS.njk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync-templates/.github/CODEOWNERS.njk b/sync-templates/.github/CODEOWNERS.njk index 6c1a271..ad57790 100644 --- a/sync-templates/.github/CODEOWNERS.njk +++ b/sync-templates/.github/CODEOWNERS.njk @@ -1,4 +1,4 @@ -{#- Remove leading dot if present (e.g., ".github" → "github") -#} +{#- Remove leading dot if present (e.g., ".github" -> "github") -#} {%- set repo_name = repo.name | replace(r/^\./, '') -%} {%- set maintainers = maintainers-prefix + repo_name -%} {%- set approvers = approvers-prefix + repo_name -%} From 3ff3cdef8e20d33b792aba0a4e5ee7514cab7101 Mon Sep 17 00:00:00 2001 From: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> Date: Wed, 10 Dec 2025 21:54:44 +0000 Subject: [PATCH 12/14] fix: correct variable naming for maintainers and approvers prefixes in CODEOWNERS template Signed-off-by: GitHub Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> --- .github/sync.yml | 4 ++-- sync-templates/.github/CODEOWNERS.njk | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/sync.yml b/.github/sync.yml index e42d2a1..21741d3 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -33,8 +33,8 @@ group: - source: sync-templates/.github/CODEOWNERS.njk dest: .github/CODEOWNERS template: - maintainers-prefix: "@radius-project/maintainers-" - approvers-prefix: "@radius-project/approvers-" + maintainers_prefix: "@radius-project/maintainers-" + approvers_prefix: "@radius-project/approvers-" oncall: "@radius-project/on-call" - source: workflow-templates/dependency-review.yml diff --git a/sync-templates/.github/CODEOWNERS.njk b/sync-templates/.github/CODEOWNERS.njk index ad57790..e08129e 100644 --- a/sync-templates/.github/CODEOWNERS.njk +++ b/sync-templates/.github/CODEOWNERS.njk @@ -1,7 +1,7 @@ {#- Remove leading dot if present (e.g., ".github" -> "github") -#} -{%- set repo_name = repo.name | replace(r/^\./, '') -%} -{%- set maintainers = maintainers-prefix + repo_name -%} -{%- set approvers = approvers-prefix + repo_name -%} +{%- set repo_name = repo.name | replace(".", "") -%} +{%- set maintainers = maintainers_prefix + repo_name -%} +{%- set approvers = approvers_prefix + repo_name -%} # Code Owners for {{ repo.fullName }} # Generated from template - do not edit directly From 72c9a35400730db44232fd9c15b636428943d474 Mon Sep 17 00:00:00 2001 From: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> Date: Mon, 26 Jan 2026 12:03:16 -0800 Subject: [PATCH 13/14] chore: update references Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> --- .github/sync.yml | 2 +- .github/workflows/sync.yml | 2 +- eng/SYNC.md | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/sync.yml b/.github/sync.yml index 21741d3..38304a3 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -1,5 +1,5 @@ # yaml-language-server: $schema=https://raw.githubusercontent.com/raven-actions/repo-files-sync/main/sync.schema.json -# docs: https://github.com/PaddleHQ/repo-file-sync-action?tab=readme-ov-file#advanced-sync-config +# docs: https://github.com/raven-actions/repo-files-sync?tab=readme-ov-file#advanced-sync-config # nunjucks template: https://mozilla.github.io/nunjucks/templating.html --- group: diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml index 2c64f0d..a2fe9af 100644 --- a/.github/workflows/sync.yml +++ b/.github/workflows/sync.yml @@ -52,7 +52,7 @@ jobs: set-env: false - name: Run Repo File Sync - uses: PaddleHQ/repo-file-sync-action@fb024b6e51a36213d16cc4b2c3b51c73b2b5ca70 # v1.26.13 + uses: raven-actions/repo-files-sync@a32d49a3138401b885770be18ee22d31c6faf7fb with: GH_INSTALLATION_TOKEN: ${{ steps.get-token.outputs.token }} CONFIG_PATH: ./.github/sync.yml diff --git a/eng/SYNC.md b/eng/SYNC.md index 68b3819..54d526b 100644 --- a/eng/SYNC.md +++ b/eng/SYNC.md @@ -72,7 +72,7 @@ flowchart TB sync_workflow -->|"Triggered on push to main
(when sync-related files change)"| sync_action - sync_action["PaddleHQ/repo-file-sync-action
Creates PRs in target repositories"] + sync_action["raven-actions/repo-files-sync
Creates PRs in target repositories"] sync_action --> repo_a["org/repo-a"] sync_action --> repo_b["org/repo-b"] @@ -129,7 +129,7 @@ The sync workflow (`.github/workflows/sync.yml`) is triggered when: - `pull-requests: write` - `workflows: write` 1. **Bot Identity**: Retrieves bot details for commit attribution -1. **File Sync**: Uses [PaddleHQ/repo-file-sync-action](https://github.com/PaddleHQ/repo-file-sync-action) to: +1. **File Sync**: Uses [raven-actions/repo-files-sync](https://github.com/raven-actions/repo-files-sync) to: - Read the sync configuration from `.github/sync.yml` - Create branches (prefixed with `repo-sync`) in target repos - Copy files from source to destination paths @@ -374,7 +374,7 @@ The sync action creates PRs, not direct commits. If conflicts occur: ## References -- [PaddleHQ/repo-file-sync-action](https://github.com/PaddleHQ/repo-file-sync-action) - The sync action used +- [raven-actions/repo-files-sync](https://github.com/raven-actions/repo-files-sync) - The sync action used - [Creating workflow templates](https://docs.github.com/en/actions/how-tos/reuse-automations/create-workflow-templates) - GitHub docs - [Reusable workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows) - GitHub docs - [GitHub Apps](https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/about-creating-github-apps) - Authentication method From 545bfe063e3607199a7dd6b1de609dcc39a997ad Mon Sep 17 00:00:00 2001 From: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> Date: Wed, 28 Jan 2026 15:27:55 -0800 Subject: [PATCH 14/14] feat: add shell scripting instructions and guidelines Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com> --- .github/sync.yml | 7 + .../instructions/shell.instructions.md | 199 ++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 sync-templates/.github/instructions/shell.instructions.md diff --git a/.github/sync.yml b/.github/sync.yml index 38304a3..950c18f 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -39,3 +39,10 @@ group: - source: workflow-templates/dependency-review.yml dest: .github/workflows/dependency-review.yml + + - repos: | + radius-project/design-notes + radius-project/radius + files: + - source: sync-templates/.github/instructions/shell.instructions.md + dest: .github/instructions/shell.instructions.md diff --git a/sync-templates/.github/instructions/shell.instructions.md b/sync-templates/.github/instructions/shell.instructions.md new file mode 100644 index 0000000..d03617b --- /dev/null +++ b/sync-templates/.github/instructions/shell.instructions.md @@ -0,0 +1,199 @@ +--- +applyTo: "**/*.sh" +description: Instructions for shell script implementation using Bash conventions +--- + +# Shell Scripting Instructions + +Instructions for writing clean, safe, and maintainable shell scripts for bash, sh, zsh, and other shells. + +## General Principles + +- Generate code that is clean, simple, and concise +- Ensure scripts are easily readable and understandable +- Keep comments to a minimum, only add comments when the logic may be confusing (regex, complex if statements, confusing variables, etc.) +- Generate concise and simple echo outputs to provide execution status +- Avoid unnecessary echo output and excessive logging +- Always strive to keep bash and shell code simple and well crafted +- Only add functions when needed to simplify logic +- Use shellcheck for static analysis when available +- Assume scripts are for automation and testing rather than production systems unless specified otherwise +- Use the correct and latest conventions for Bash, version 5.3 release +- Prefer safe expansions: double-quote variable references (`"$var"`), use `${var}` for clarity, and avoid `eval` +- Use modern Bash features (`[[ ]]`, `local`, arrays) when portability requirements allow; fall back to POSIX constructs only when needed +- Choose reliable parsers for structured data instead of ad-hoc text processing + +## Error Handling & Safety + +### Core Safety Principles + +- Always enable `set -euo pipefail` to fail fast on errors, catch unset variables, and surface pipeline failures +- Validate all required parameters before execution +- Provide clear error messages with context +- Use `trap` to clean up temporary resources or handle unexpected exits when the script terminates +- Declare immutable values with `readonly` (or `declare -r`) to prevent accidental reassignment +- Use `mktemp` to create temporary files or directories safely and ensure they are removed in your cleanup handler + +### Error Handling and Output Guidelines + +When it's obvious errors should be visible or users explicitly request that errors be visible: + +- NEVER redirect stderr to `/dev/null` or suppress error output +- Allow commands to fail naturally and show their native error messages +- Use `|| echo ""` pattern only when you need to capture output but allow graceful failure +- Prefer natural bash error propagation over complex error capture and re-display +- Let tools like `az login` fail naturally with their built-in error messages + +## Script Structure + +- Start with a clear shebang: `#!/bin/bash` unless specified otherwise +- Include a header comment explaining the script's purpose +- Define default values for all variables at the top +- Use functions for reusable code blocks +- Create reusable functions instead of repeating similar blocks of code +- Keep the main execution flow clean and readable + +### Script Template Example + +```bash +#!/bin/bash + +# ============================================================================ +# Script Description Here +# ============================================================================ + +set -euo pipefail + +cleanup() { + # Remove temporary resources or perform other teardown steps as needed + if [[ -n "${TEMP_DIR:-}" && -d "${TEMP_DIR}" ]]; then + rm -rf "${TEMP_DIR}" + fi +} + +trap cleanup EXIT + +# Default values +RESOURCE_GROUP="" +REQUIRED_PARAM="" +OPTIONAL_PARAM="default-value" +readonly SCRIPT_NAME="$(basename "$0")" + +TEMP_DIR="" + +# Functions +usage() { + echo "Usage: ${SCRIPT_NAME} [OPTIONS]" + echo "Options:" + echo " -g, --resource-group Resource group (required)" + echo " -h, --help Show this help" + exit 0 +} + +validate_requirements() { + if [[ -z "${RESOURCE_GROUP}" ]]; then + echo "Error: Resource group is required" + exit 1 + fi +} + +main() { + validate_requirements + + TEMP_DIR="$(mktemp -d)" + if [[ ! -d "${TEMP_DIR}" ]]; then + echo "Error: failed to create temporary directory" >&2 + exit 1 + fi + + echo "============================================================================" + echo "Script Execution Started" + echo "============================================================================" + + # Main logic here + + echo "============================================================================" + echo "Script Execution Completed" + echo "============================================================================" +} + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + -g | --resource-group) + RESOURCE_GROUP="$2" + shift 2 + ;; + -h | --help) + usage + ;; + *) + echo "Unknown option: $1" + exit 1 + ;; + esac +done + +# Execute main function +main "$@" +``` + +## Working with JSON and YAML + +- Prefer dedicated parsers (`jq` for JSON, `yq` for YAML - or `jq` on JSON converted via `yq`) over ad-hoc text processing with `grep`, `awk`, or shell string splitting +- When `jq`/`yq` are unavailable or not appropriate, choose the next most reliable parser available in your environment, and be explicit about how it should be used safely +- Validate that required fields exist and handle missing/invalid data paths explicitly (e.g., by checking `jq` exit status or using `// empty`) +- Quote jq/yq filters to prevent shell expansion and prefer `--raw-output` when you need plain strings +- Treat parser errors as fatal: combine with `set -euo pipefail` or test command success before using results +- Document parser dependencies at the top of the script and fail fast with a helpful message if `jq`/`yq` (or alternative tools) are required but not installed + +## Azure CLI and JMESPath Guidelines + +When working with Azure CLI: + +- Research Azure CLI command output structure using #fetch: +- Understand JMESPath syntax thoroughly using #fetch: +- Test JMESPath queries with actual Azure CLI output structure +- Use #githubRepo:"Azure/azure-cli" to research specific Azure CLI behaviors + +## ShellCheck and Formatting Compliance + +You will always follow all shellcheck and shfmt formatting rules: + +- ALWAYS use the get_errors #problems tool to check for linting issues in shell files you are working on +- Use `shellcheck` command line tool only when get_errors #problems tool is not available +- Always follow Shell Style Guide formatting rules from #fetch: +- `shellcheck` is located at #githubRepo:"koalaman/shellcheck" search there for more information +- For all shellcheck rules #fetch: +- Always check the get_errors #problems tool for any issues with the specific shell or bash file being modified before AND after making changes + +### Formatting Rules (Shell Style Guide) + +Follow these formatting conventions along with all others outlined in #fetch:: + +- Use 4 spaces for indentation, never tabs +- Maximum line length is 80 characters +- Put `; then` and `; do` on the same line as `if`, `for`, `while` +- Use `[[ ... ]]` instead of `[ ... ]` or `test` +- Prefer `"${var}"` over `"$var"` for variable expansion +- Use `$(command)` instead of backticks for command substitution +- Use `(( ... ))` for arithmetic operations instead of `let` or `expr` +- Quote all variable expansions unless you specifically need word splitting +- Use arrays for lists of elements: `declare -a array=(item1 item2)` +- Use `local` for function-specific variables +- Function names: lowercase with underscores `my_function()` +- Constants: uppercase with underscores `readonly MY_CONSTANT="value"` + +## Research and Validation Requirements + +Before making changes to shell scripts: + +- Use #fetch to research Azure CLI documentation when working with `az` commands +- Use #githubRepo to research Azure CLI source code for complex scenarios +- Always validate your understanding of command output formats +- Test complex logic patterns and JMESPath queries before implementation +- Understand the user's specific requirements about error handling and output visibility + +--- + +