Skip to content

feat(labels): support exclusion regexp - #408

Merged
decyjphr merged 2 commits into
github-community-projects:main-enterprisefrom
anderssonjohan:labels-exclude-existing
Feb 22, 2023
Merged

feat(labels): support exclusion regexp#408
decyjphr merged 2 commits into
github-community-projects:main-enterprisefrom
anderssonjohan:labels-exclude-existing

Conversation

@anderssonjohan

Copy link
Copy Markdown
Contributor

fixes #407
fixes #398

Adds support for alternative labels configuration where labels matching a given pattern can be excluded from delete operations. This allows other tools to create labels without having them deleted by safe-settings.

Example: The following config would keep the labels released, released on @dev, released on @7.x created by a tool such as Semantic Release.

labels:
  include:
    - name: bug
      color: '#ff0000'
  exclude:
    - name: ^release

Include can be used without specifying exclude in the config, while also supporting the current format:

labels:
  - name: bug
    color: '#ff0000'

@anderssonjohan

Copy link
Copy Markdown
Contributor Author

ping @decyjphr @martinm82 Does this make sense?

It occurred to me that the plugin is given the object from the config at the plugin level and not the whole config so instead of having a separate root config node it felt it made more sense to keep it in the labels plugin configuration rather than as a separate config key like I mentioned in the discussion thread.

It's only to exclude labels from being deleted but I thought using the include and exclude keys were the best way of turning the current array config to an object and making it similar to other parts of the configuration.

Other options considered and scrapped:

labels:
  exclude: regexp-pattern
  labels:
    - name: ....
      color: ...
labels:
  - exclude: regexp-pattern1
  - exclude: regexp-pattern2
  - name: label1
    color: ...
  - name: label2
    color: ...

Note: Unintentional white-space update of the README by my editor, let me know if you want me to redo the documentation update without the white-space update.

@anderssonjohan
anderssonjohan force-pushed the labels-exclude-existing branch from 6fb6f71 to 9de8e1a Compare February 10, 2023 18:14
@anderssonjohan

anderssonjohan commented Feb 10, 2023

Copy link
Copy Markdown
Contributor Author

Maybe an unexpected side-effect depending on the config values:
Using any of the following exclusion patterns will disable the deletion of any label, even the ones defined in include.

labels:
  exclude:
    - .
    - '[^]'

@martinm82

Copy link
Copy Markdown
Contributor

Maybe an unexpected side-effect depending on the config values: Using any of the following exclusion patterns will disable the deletion of any label, even the ones defined in include.

labels:
  exclude:
    - .
    - '[^]'

This is in my opinion a very nice addition and we should have this feature as well on topics (can be a separate PR if preferred). WDYT?

@anderssonjohan

Copy link
Copy Markdown
Contributor Author

I took the liberty to create a separate feature request for your suggestion about topics: #411

@martinm82

martinm82 commented Feb 15, 2023

Copy link
Copy Markdown
Contributor

@anderssonjohan what do you think about documenting it in the README?

@martinm82

Copy link
Copy Markdown
Contributor

I was thinking a bit more about this and I am wondering whether the default behaviour should be to keep labels/topics and update with the ones managed in safe-settings.

In our case we have 9k repositories and started just recently using safe-settings. I cannot manage labels on org level since as of now it will delete all manually created ones. I believe that having the "do not delete" behaviour as default makes the transition to safe-settings much safer. WDYT?

Also, would be good to spit out in debug logs those labels that are not tracked by safe-settings. Later teams can get those from the logs (splunk, dataset, Loki, etc.) and migrate them over to safe-settings.

@anderssonjohan

Copy link
Copy Markdown
Contributor Author

@anderssonjohan what do you think about documenting it in the README?

@martinm82 Do you mean documenting both syntax options? The (non-whitespace) change I made to the README in this PR was modifying the sample to use include/exclude for labels: https://github.com/github/safe-settings/pull/408/files#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L325

@decyjphr

Copy link
Copy Markdown
Collaborator

@anderssonjohan this is a cool (and valuable) feature. Thank you. I'll test it and merge it.

@martinm82

Copy link
Copy Markdown
Contributor

@anderssonjohan what do you think about documenting it in the README?

@martinm82 Do you mean documenting both syntax options? The (non-whitespace) change I made to the README in this PR was modifying the sample to use include/exclude for labels: https://github.com/github/safe-settings/pull/408/files#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L325

Sorry, I missed that between all the whitespaces changes.

@martinm82 martinm82 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

@adrianschmidt

adrianschmidt commented Feb 17, 2023

Copy link
Copy Markdown

@anderssonjohan what do you think about documenting it in the README?

@martinm82 Do you mean documenting both syntax options? The (non-whitespace) change I made to the README in this PR was modifying the sample to use include/exclude for labels: #408 (files)

Sorry, I missed that between all the whitespaces changes.

I think Johan is about to provide an updated version without the whitespace changes, so I'd wait for that before merging 🙂

Adds support for alternative labels configuration where
labels matching a given pattern can be excluded from
delete operations. This allows other tools to create
labels without having them deleted by safe-settings.

Example: The following config would keep the labels
`released`, `released on @dev`, `released on @7.x`
created by a tool such as Semantic Release.

```
labels:
  include:
    - name: bug
      color: '#ff0000'
  exclude:
    - name: ^release
```

Include can be used without specifying exclude in the
config, while also supporting the current format:

```
labels:
  - name: bug
    color: '#ff0000'
```
@anderssonjohan
anderssonjohan force-pushed the labels-exclude-existing branch from 9de8e1a to 70d1c95 Compare February 20, 2023 16:34
@anderssonjohan

anderssonjohan commented Feb 20, 2023

Copy link
Copy Markdown
Contributor Author

Sorry for the late response to this. Now ready for merge @decyjphr

Thank you @adrianschmidt for pointing out that two trailing spaces means hard newline in Markdown!
I guess the (default) Markdown formatter used in VSCode has a no hard-break-spaces rule and just strips them.
(The readme.md in this repo both have single and double spaces at EOLs)

Anyhow, readme now only have the intended change for the labels example.

EDIT: For the one also bitten by the VSCode formatter: microsoft/vscode#1679 (comment)

@decyjphr

Copy link
Copy Markdown
Collaborator

@anderssonjohan for the existing configurations, Would this be a breaking change, i.e. they have to modify the labels section to move the current entries under the includes: subsection? Or would this change be backward compatible?

@anderssonjohan

Copy link
Copy Markdown
Contributor Author

@anderssonjohan for the existing configurations, Would this be a breaking change, i.e. they have to modify the labels section to move the current entries under the includes: subsection? Or would this change be backward compatible?

@decyjphr Thanks for asking! it's backwards compatible by checking if the include is an array or not here: https://github.com/github/safe-settings/pull/408/files#diff-e71ad8761eefa8f71d7f5c23541f2078574ae83d48423be0d06dd16740d43cc3R8
Thus, it should be safe without being a breaking change.

@decyjphr
decyjphr merged commit dbd45e0 into github-community-projects:main-enterprise Feb 22, 2023
@martinm82

Copy link
Copy Markdown
Contributor

I was thinking a bit more about this and I am wondering whether the default behaviour should be to keep labels/topics and update with the ones managed in safe-settings.

In our case we have 9k repositories and started just recently using safe-settings. I cannot manage labels on org level since as of now it will delete all manually created ones. I believe that having the "do not delete" behaviour as default makes the transition to safe-settings much safer. WDYT?

Also, would be good to spit out in debug logs those labels that are not tracked by safe-settings. Later teams can get those from the logs (splunk, dataset, Loki, etc.) and migrate them over to safe-settings.

Actually, you can easily get this default behaviour by adding the exclude in the org settings.

@martinm82

Copy link
Copy Markdown
Contributor

@anderssonjohan I have been playing around with the exclude pattern (#408 (comment)) and it seems that if a repo is already managed with safe-settings and you create a label manually the first time it gets still deleted. The next time you create it again, safe-settings does not touch it again.
Have you seen this behaviour as well?

@anderssonjohan

Copy link
Copy Markdown
Contributor Author

@anderssonjohan I have been playing around with the exclude pattern (#408 (comment)) and it seems that if a repo is already managed with safe-settings and you create a label manually the first time it gets still deleted. The next time you create it again, safe-settings does not touch it again. Have you seen this behaviour as well?

No, sorry, nothing that I've seen. Are you sure it got the webhook notification etc the second time?

@svg153 svg153 mentioned this pull request Nov 2, 2023
jordonpeterson added a commit to jordonpeterson/safe-settings that referenced this pull request Jul 27, 2026
…d property values

Custom properties cannot be deleted through the API, so Diffable's removal
path sets `value: null`. Any property present on a repository but absent from
config was therefore cleared on every sync, including values written by other
automation. Safe-settings effectively claimed exclusive ownership of the whole
custom-properties surface on any repo with a `custom_properties` section.

Adds the `include`/`exclude` config shape already used by the Labels plugin
(github-community-projects#408). Properties matching an `exclude` regex are never cleared; properties
listed in `include` are enforced exactly as before, even if they also match an
exclude pattern. The plain-array config shape is unchanged.

Unlike Labels, an unparseable exclude regex is recorded as a per-repo config
error and skipped rather than thrown. Child plugins are constructed outside any
try/catch in Settings.updateRepos, so a throw there rejects the org-wide
Promise.all and aborts the sync for every other repo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jordonpeterson added a commit to jordonpeterson/safe-settings that referenced this pull request Jul 27, 2026
…d property values

Custom properties cannot be deleted through the API, so Diffable's removal
path sets `value: null`. Any property present on a repository but absent from
config was therefore cleared on every sync, including values written by other
automation. Safe-settings effectively claimed exclusive ownership of the whole
custom-properties surface on any repo with a `custom_properties` section.

Adds the `include`/`exclude` config shape already used by the Labels plugin
(github-community-projects#408). Properties matching an `exclude` regex are never cleared; properties
listed in `include` are enforced exactly as before, even if they also match an
exclude pattern. The plain-array config shape is unchanged.

Both config-error paths are designed to fail safe, because the cost of
misreading an exclude pattern is cleared property values:

* Exclude patterns are lowercased when compiled. Property names are lowercased
  before matching, so an uppercase pattern would otherwise be a valid regex
  that silently matches nothing and clears the properties it was written to
  protect.

* An unparseable pattern is recorded as a per-repo config error and fails
  closed - every property on that repo is treated as excluded, so a typo
  protects values rather than clearing them. This matters because these are
  regexes, not globs: the intuitive `*` is not a valid pattern. Properties in
  `include` are still applied. The error is not thrown, because child plugins
  are constructed outside any try/catch in Settings.updateRepos, so a throw
  there rejects the org-wide Promise.all and aborts the sync for every other
  repo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jordonpeterson added a commit to jordonpeterson/safe-settings that referenced this pull request Jul 27, 2026
…d property values

Custom properties cannot be deleted through the API, so Diffable's removal
path sets `value: null`. Any property present on a repository but absent from
config was therefore cleared on every sync, including values written by other
automation. Safe-settings effectively claimed exclusive ownership of the whole
custom-properties surface on any repo with a `custom_properties` section.

Adds the `include`/`exclude` config shape already used by the Labels plugin
(github-community-projects#408). Properties matching an `exclude` regex are never cleared; properties
listed in `include` are enforced exactly as before, even if they also match an
exclude pattern. The plain-array config shape is unchanged.

Both config-error paths are designed to fail safe, because the cost of
misreading an exclude pattern is cleared property values:

* Exclude patterns are lowercased when compiled. Property names are lowercased
  before matching, so an uppercase pattern would otherwise be a valid regex
  that silently matches nothing and clears the properties it was written to
  protect.

* An unparseable pattern is recorded as a per-repo config error and fails
  closed - every property on that repo is treated as excluded, so a typo
  protects values rather than clearing them. This matters because these are
  regexes, not globs: the intuitive `*` is not a valid pattern. Properties in
  `include` are still applied. The error is not thrown, because child plugins
  are constructed outside any try/catch in Settings.updateRepos, so a throw
  there rejects the org-wide Promise.all and aborts the sync for every other
  repo.

* The object form requires `include`, `exclude`, or both. A config that is
  neither the array shape nor the include/exclude shape (`custom_properties: {}`,
  say) is reported and also fails closed. The schemas reject that shape too, but
  they are authoring aids rather than a runtime gate - nothing in lib/ validates
  config against them - so the plugin does not rely on them. Without this the
  empty object reached `normalizeEntries` and threw a TypeError out of the
  constructor, which is the org-wide abort described above.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Labels test fails due to change in requirement

4 participants