Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .github/workflows/label_sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: "Labels: Sync"

on:
workflow_dispatch:
inputs:
dry-run:
description: "Preview label changes without applying them"
required: false
type: boolean
default: true
repos:
description: >-
Optional comma-separated list of repos to target.
Leave empty to target all repos except complytime and roadmap.
required: false
type: string
default: ""

permissions:
contents: read

concurrency:
group: label-sync
cancel-in-progress: false

jobs:
sync-labels:
if: github.repository_owner == 'complytime'
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
steps:
- name: Checkout complytime/.github repo
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Setup Python
uses: actions/setup-python@42375524a786f35ee56e4dbe431d0097254bc67c # v6.0.0
with:
python-version: "3.13"

- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ secrets.COMPLYTIME_BOT_CLIENT_ID }}
private-key: ${{ secrets.COMPLYTIME_BOT_PRIVATE_KEY }}
owner: complytime

- name: Sync labels
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
INPUT_REPOS: ${{ inputs.repos }}
DRY_RUN: ${{ inputs.dry-run }}
run: |
set -eu

REPO_ARGS=""
if [ -n "$INPUT_REPOS" ]; then
CLEANED=$(printf '%s' "$INPUT_REPOS" | tr ',' ' ')
REPO_ARGS="--repos $CLEANED"
fi

if [ "$DRY_RUN" = "true" ]; then
DRY_ARG="--dry-run"
else
DRY_ARG=""
fi

# shellcheck disable=SC2086
python3 scripts/sync_labels.py \
--policy labels-policy.json \
$DRY_ARG \
$REPO_ARGS
22 changes: 22 additions & 0 deletions MAINTAINING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ GitHub organization using two complementary tools: **peribolos** and
| Dependabot alerts and fixes | safe-settings | `safe-settings/settings.yml` |
| Branch protection rules | safe-settings | `safe-settings/settings.yml` |
| Rulesets | safe-settings | `safe-settings/settings.yml` |
| Cross-repo label standardization | custom workflow | `labels-policy.json`, `scripts/sync_labels.py` |
| `.github` repo ruleset | **manual** | GitHub UI |

**Why two tools?** Peribolos manages org-level concerns (who is a member,
Expand Down Expand Up @@ -88,6 +89,20 @@ that differ from its suborg defaults.
See `safe-settings/repos/complyctl.yml` for an example (complyctl requires
2 approvers instead of the org default of 1).

### Reconcile Labels Across Repositories

Use the **"Labels: Sync"** workflow for label-only changes that do not fit
safe-settings' "apply everything in this config" model.

The workflow reads `labels-policy.json` and applies three kinds of changes:

1. Ensure a shared set of standard labels exists everywhere.
2. Rename legacy labels only in repositories where they already exist.
3. Delete only explicitly-listed labels, leaving all other local labels alone.

This is useful when some labels must remain repo-specific and should not be
replicated across the organization.

## Override Validator Policies

Override validators in `safe-settings/deployment-settings.yml` enforce
Expand Down Expand Up @@ -219,6 +234,13 @@ Go to Actions > "Safe Settings Sync" > "Run workflow":
`complytime-demos,community`). Leave empty to apply to all managed
repos.

### Labels

Go to Actions > "Labels: Sync" > "Run workflow":
- **dry-run**: `true` to preview, `false` to apply (defaults to `true`)
- **repos**: comma-separated list of repos to target. Leave empty to apply
to all repos except those excluded in `labels-policy.json`

### Future automation

After initial validation, the workflow can be extended with:
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ complementary tools:
— org membership, teams, and team-repo permissions (`peribolos.yaml`)
- **[safe-settings](https://github.com/github/safe-settings)** — repository
settings, branch protection, rulesets, and security config (`safe-settings/`)
- **Custom label sync** — targeted repository label normalization and cleanup
(`labels-policy.json`, `scripts/sync_labels.py`)

For maintainer workflows, local testing, and troubleshooting, see
**[MAINTAINING.md](MAINTAINING.md)**.
Expand Down
199 changes: 199 additions & 0 deletions labels-policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
{
"org": "complytime",
"exclude_repos": [
"complytime",
"roadmap"
],
"preserve_local_only_labels": [
"60 day implementation",
"Fedora",
"ISO 42001 audit",
"RHEL Sec Compliance",
"automated",
"branch protection rules",
"ci",
"go",
"javascript",
"newsletter",
"peribolos-drift",
"post 60 day implementation",
"pre_commit",
"python",
"private-sprint-sub-issue"
],
"rename_only_labels": [
{
"from": [
"60 days"
],
"to": {
"name": "60 day implementation",
"color": "d4c5f9",
"description": "Tracking work scheduled for the 60 day implementation window."
}
},
{
"from": [
"clean up"
],
"to": {
"name": "Clean up",
"color": "fbca04",
"description": "Maintenance work that cleans up existing code, config, or process."
}
},
{
"from": [
"test"
],
"to": {
"name": "Test",
"color": "0e8a16",
"description": "Changes or work focused on testing."
}
},
{
"from": [
"uat"
],
"to": {
"name": "UAT",
"color": "1d76db",
"description": "User acceptance testing and validation work."
}
},
{
"from": [
"docker"
],
"to": {
"name": "container",
"color": "5319e7",
"description": "Container image, container runtime, or container packaging work."
}
},
{
"from": [
"llm_assisted"
],
"to": {
"name": "AI assisted",
"color": "bfd4f2",
"description": "Work created or updated with AI assistance."
}
},
{
"from": [
"post 60 days"
],
"to": {
"name": "post 60 day implementation",
"color": "f9d0c4",
"description": "Tracking work scheduled after the 60 day implementation window."
}
},
{
"from": [
"question",
"to validate",
"to validade"
],
"to": {
"name": "validate",
"color": "fbca04",
"description": "Work that still needs validation before it is complete."
}
}
],
"delete_labels": [
"Risk",
"Unbound force",
"autorelease: pending",
"autorelease: tagged",
"baklava sprint 8",
"breaking_change",
"complyctl-import",
"complyctl-plugins",
"complyscribe-imported",
"private",
"proposal",
"research"
],
"standard_labels": [
{
"name": "Bug",
"color": "d73a4a",
"description": "Something is broken and needs to be fixed."
},
{
"name": "Dependencies",
"color": "0366d6",
"description": "Dependency updates or dependency management work."
},
{
"name": "documentation",
"color": "0075ca",
"description": "Improvements or additions to documentation."
},
{
"name": "Duplicate",
"color": "cfd3d7",
"description": "This issue or pull request already exists elsewhere."
},
{
"name": "Enhancement",
"color": "a2eeef",
"description": "New functionality, optimization, or an improvement to existing behavior."
},
{
"name": "Github_actions",
"color": "5319e7",
"description": "Changes related to GitHub Actions workflows or automation."
},
{
"name": "good first issue",
"color": "7057ff",
"description": "A good entry point for first-time contributors."
},
{
"name": "help wanted",
"color": "008672",
"description": "Extra attention is needed from contributors or maintainers."
},
{
"name": "Invalid",
"color": "e4e669",
"description": "This issue or pull request is not valid as filed."
},
{
"name": "Maintenance",
"color": "fbca04",
"description": "Routine maintenance or upkeep work."
},
{
"name": "Security",
"color": "b60205",
"description": "Security-related work, fixes, or hardening."
},
{
"name": "Ux",
"color": "1d76db",
"description": "User experience, usability, or interaction design work."
},
{
"name": "Wontfix",
"color": "ffffff",
"description": "This will not be worked on or accepted."
},
{
"name": "stakeholder",
"color": "0e8a16",
"description": "Requires input from or coordination with project stakeholders."
},
{
"name": "needs-adr",
"color": "5319e7",
"description": "An architecture decision record is needed before proceeding."
}
]
}
Loading
Loading