way_of_working 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -1
- data/CONTRIBUTING.md +62 -0
- data/README.md +187 -14
- data/lib/way_of_working/audit/github/auditor.rb +44 -0
- data/lib/way_of_working/audit/github/generators/exec.rb +163 -0
- data/lib/way_of_working/audit/github/rules/base.rb +91 -0
- data/lib/way_of_working/audit/github/rules/registry.rb +36 -0
- data/lib/way_of_working/audit/github/rules/unknown.rb +19 -0
- data/lib/way_of_working/audit/github.rb +25 -0
- data/lib/way_of_working/changelog/keepachangelog/generators/init.rb +118 -0
- data/lib/way_of_working/changelog/keepachangelog/github_audit_rule.rb +32 -0
- data/lib/way_of_working/changelog/keepachangelog/templates/docs/way_of_working/changelog.md +73 -0
- data/lib/way_of_working/changelog/keepachangelog.rb +35 -0
- data/lib/way_of_working/code_of_conduct/contributor_covenant/generators/init.rb +39 -0
- data/lib/way_of_working/code_of_conduct/contributor_covenant/github_audit_rule.rb +32 -0
- data/lib/way_of_working/code_of_conduct/contributor_covenant/templates/CODE_OF_CONDUCT.md.tt +133 -0
- data/lib/way_of_working/code_of_conduct/contributor_covenant/templates/docs/way_of_working/code-of-conduct.md +78 -0
- data/lib/way_of_working/code_of_conduct/contributor_covenant.rb +36 -0
- data/lib/way_of_working/decision_record/madr/generators/init.rb +41 -0
- data/lib/way_of_working/decision_record/madr/generators/new.rb +69 -0
- data/lib/way_of_working/decision_record/madr/github_audit_rule.rb +50 -0
- data/lib/way_of_working/decision_record/madr/templates/.github/ISSUE_TEMPLATE/decision-record.md +26 -0
- data/lib/way_of_working/decision_record/madr/templates/docs/decisions/0000-use-markdown-any-decision-records.md +30 -0
- data/lib/way_of_working/decision_record/madr/templates/docs/decisions/README.md +7 -0
- data/lib/way_of_working/decision_record/madr/templates/docs/decisions/adr-template.md.tt +82 -0
- data/lib/way_of_working/decision_record/madr/templates/docs/decisions/index.md +48 -0
- data/lib/way_of_working/decision_record/madr/templates/docs/way_of_working/decision-records.md +195 -0
- data/lib/way_of_working/decision_record/madr.rb +53 -0
- data/lib/way_of_working/git/repo_reader.rb +2 -2
- data/lib/way_of_working/inclusive_language/alex/generators/exec.rb +51 -0
- data/lib/way_of_working/inclusive_language/alex/generators/init.rb +34 -0
- data/lib/way_of_working/inclusive_language/alex/github_audit_rule.rb +35 -0
- data/lib/way_of_working/inclusive_language/alex/templates/.alexignore +2 -0
- data/lib/way_of_working/inclusive_language/alex/templates/.alexrc +3 -0
- data/lib/way_of_working/inclusive_language/alex/templates/.github/workflows/inclusive-language.yml +16 -0
- data/lib/way_of_working/inclusive_language/alex/templates/docs/way_of_working/inclusive-language.md +28 -0
- data/lib/way_of_working/inclusive_language/alex.rb +48 -0
- data/lib/way_of_working/pull_request_template/hdi/generators/init.rb +26 -0
- data/lib/way_of_working/pull_request_template/hdi/github_audit_rule.rb +32 -0
- data/lib/way_of_working/pull_request_template/hdi/templates/.github/pull_request_template.md +51 -0
- data/lib/way_of_working/pull_request_template/hdi/templates/docs/way_of_working/pull-request-template-and-guidelines.md +50 -0
- data/lib/way_of_working/pull_request_template/hdi.rb +35 -0
- data/lib/way_of_working/readme_badge/github_audit_rule.rb +1 -3
- data/lib/way_of_working/readme_badge/paths.rb +5 -2
- data/lib/way_of_working/readme_badge.rb +5 -7
- data/lib/way_of_working/version.rb +1 -1
- data/lib/way_of_working/versioning/semver/generators/init.rb +20 -0
- data/lib/way_of_working/versioning/semver/github_audit_rule.rb +49 -0
- data/lib/way_of_working/versioning/semver/templates/docs/way_of_working/versioning.md +71 -0
- data/lib/way_of_working/versioning/semver.rb +35 -0
- data/lib/way_of_working.rb +15 -0
- data/way_of_working.gemspec +4 -1
- metadata +89 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a018ad36100c846ff6876cd4db5a6228fca2c0264b505971795559dd75a39d3b
|
|
4
|
+
data.tar.gz: 69cb609754aba06b2fd2b3b99171cf3cb09c84651a3986aad054f9121664eca5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cf11254e92ca8b5da97f8f77aecbcf1f3883b83d8c0aa3fd7ba51a5ac7720ff4fa4bb6a65f32fe634d2e08c250a8522997cfadd6856820aee59a7c59dec7dd8d
|
|
7
|
+
data.tar.gz: a7b8040aa306c657a8691ad3ce7061a4a42073ab1ac0124b2187ed6bc40f9f3411d58621c6db1d22f646534e73585d1646aeea94dd8bdb21be57381b4ff6c41c
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.1.0] - 2026-06-08
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Audit:** bundled the GitHub audit feature into this gem. It is opt in and replaces the separate `way_of_working-audit-github` plugin gem.
|
|
15
|
+
- **Changelog:** bundled the Keep a Changelog feature into this gem. It is opt in and replaces the separate `way_of_working-changelog-keepachangelog` plugin gem.
|
|
16
|
+
- **Code of Conduct:** bundled the Contributor Covenant feature into this gem. It is opt in and replaces the separate `way_of_working-code_of_conduct-contributor_covenant` plugin gem.
|
|
17
|
+
- **Decision Records:** bundled the MADR feature into this gem. It is opt in and replaces the separate `way_of_working-decision_record-madr` plugin gem.
|
|
18
|
+
- **Inclusive Language:** bundled the alex feature into this gem. It is opt in and replaces the separate `way_of_working-inclusive_language-alex` plugin gem.
|
|
19
|
+
- **Pull Request Template:** bundled the HDI feature into this gem. It is opt in and replaces the separate `way_of_working-pull_request_template-hdi` plugin gem.
|
|
20
|
+
- **Versioning:** bundled the Semantic Versioning feature into this gem. It is opt in and replaces the separate `way_of_working-versioning-semver` plugin gem.
|
|
21
|
+
- **Versioning:** documented the versioning policy in [ADR-0001](docs/decisions/0001-version-the-gem-interface-not-generated-content.md) and `CONTRIBUTING.md` — SemVer governs the gem's interface, not generated content; standard refreshes are minor, and drastic upgrades ship as additive variants.
|
|
22
|
+
|
|
23
|
+
## [2.0.1] - 2025-01-17
|
|
24
|
+
|
|
25
|
+
### Removed
|
|
26
|
+
|
|
27
|
+
- Removed completely unused test resource file
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- Corrected the badge rule brittle loading and signature
|
|
32
|
+
- Resolved YAML linting issues
|
|
33
|
+
|
|
34
|
+
## [2.0.0] - 2024-10-24
|
|
35
|
+
|
|
10
36
|
### Added
|
|
11
37
|
|
|
12
38
|
- Added a panel for README badges and a Way of Working badge
|
|
@@ -48,5 +74,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
48
74
|
|
|
49
75
|
- Corrected use of relative paths in the rubocop config file
|
|
50
76
|
|
|
51
|
-
[unreleased]: https://github.com/HealthDataInsight/way_of_working/compare/
|
|
77
|
+
[unreleased]: https://github.com/HealthDataInsight/way_of_working/compare/v2.1.0...HEAD
|
|
78
|
+
[2.1.0]: https://github.com/HealthDataInsight/way_of_working/compare/v2.0.1...v2.1.0
|
|
79
|
+
[2.0.1]: https://github.com/HealthDataInsight/way_of_working/compare/v2.0.0...v2.0.1
|
|
80
|
+
[2.0.0]: https://github.com/HealthDataInsight/way_of_working/compare/v1.0.0...v2.0.0
|
|
52
81
|
[1.0.0]: https://github.com/HealthDataInsight/way_of_working/releases/tag/v1.0.0
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Bug reports and pull requests are welcome on GitHub at
|
|
4
|
+
<https://github.com/HealthDataInsight/way_of_working>. This project is intended to be a safe,
|
|
5
|
+
welcoming space for collaboration, and contributors are expected to adhere to the
|
|
6
|
+
[code of conduct](CODE_OF_CONDUCT.md).
|
|
7
|
+
|
|
8
|
+
## Development
|
|
9
|
+
|
|
10
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then run `rake test` to run
|
|
11
|
+
the tests. You can also run `bin/console` for an interactive prompt that lets you experiment.
|
|
12
|
+
|
|
13
|
+
## Versioning
|
|
14
|
+
|
|
15
|
+
This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html), but SemVer here
|
|
16
|
+
governs the gem's **public interface**, not the content of the artefacts its generators emit. The
|
|
17
|
+
versioned contract is:
|
|
18
|
+
|
|
19
|
+
* the **CLI surface** — commands and their required options;
|
|
20
|
+
* the **require paths** of built-in features
|
|
21
|
+
(e.g. `require 'way_of_working/code_of_conduct/contributor_covenant'`);
|
|
22
|
+
* the **plugin registration API** (`SubCommands::*.register`, the `way_of_working-*` autoload).
|
|
23
|
+
|
|
24
|
+
Refreshing the standard a feature embeds (e.g. a new Contributor Covenant or MADR version) changes
|
|
25
|
+
generated content but not the interface, so it is **not** a major change. See
|
|
26
|
+
[ADR-0001](docs/decisions/0001-version-the-gem-interface-not-generated-content.md) for the full
|
|
27
|
+
rationale.
|
|
28
|
+
|
|
29
|
+
### Choosing the version bump
|
|
30
|
+
|
|
31
|
+
| Change | Bump |
|
|
32
|
+
| --- | --- |
|
|
33
|
+
| Rename/remove a command or required option, move a feature's require path, or change the plugin API | **MAJOR** |
|
|
34
|
+
| Refresh the standard a feature embeds; add a new feature or variant | **MINOR** |
|
|
35
|
+
| Drastic standard upgrade shipped as a **new variant** alongside the existing one | **MINOR** (additive) |
|
|
36
|
+
| Bug fix in generation or generated output | **PATCH** |
|
|
37
|
+
|
|
38
|
+
For a standard update drastic enough to surprise existing users (e.g. Contributor Covenant
|
|
39
|
+
2.1 → 3, effectively a rewrite), add a **new variant** under the feature's `category/variant`
|
|
40
|
+
namespace rather than mutating the existing one. Both variants then coexist and consumers opt in by
|
|
41
|
+
require path — keeping the change additive and leaving existing users untouched.
|
|
42
|
+
|
|
43
|
+
### Changelog convention
|
|
44
|
+
|
|
45
|
+
All notable changes are recorded in `CHANGELOG.md` following
|
|
46
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Scope feature-affecting entries with a
|
|
47
|
+
bold feature prefix so each feature's history stays greppable within the single file, e.g.:
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
- **Code of Conduct:** upgraded Contributor Covenant 2.1 → 3 via new `contributor_covenant_v3` variant
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Releasing
|
|
54
|
+
|
|
55
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new
|
|
56
|
+
version:
|
|
57
|
+
|
|
58
|
+
1. Decide the bump using the table above.
|
|
59
|
+
2. Update the version number in `lib/way_of_working/version.rb`.
|
|
60
|
+
3. Move the `[Unreleased]` changelog entries under the new version heading.
|
|
61
|
+
4. Run `bundle exec rake release`, which creates a git tag for the version, pushes the commits and
|
|
62
|
+
tag, and pushes the `.gem` file to [rubygems.org](https://rubygems.org).
|
data/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Way of Working
|
|
2
2
|
|
|
3
3
|
<!-- Way of Working: Main Badge Holder Start -->
|
|
4
|
-

|
|
5
5
|
<!-- Way of Working: Additional Badge Holder Start -->
|
|
6
6
|
<!-- Way of Working: Badge Holder End -->
|
|
7
7
|
|
|
@@ -21,14 +21,20 @@ There are subcommands that plugins hook into which enable them to add GitHub act
|
|
|
21
21
|
|
|
22
22
|
Below is a list of plugins that have been implemented so far:
|
|
23
23
|
|
|
24
|
-
| Feature | Plugin | Description
|
|
25
|
-
| --------------------- | -------------------------------------- |
|
|
26
|
-
|
|
|
27
|
-
|
|
|
28
|
-
| Code
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
24
|
+
| Feature | Plugin | Description |
|
|
25
|
+
| --------------------- | -------------------------------------- | ---------------------------------------------------------------------------------------|
|
|
26
|
+
| Audit | Built-in (audit/github) | A framework for rules to check for incorrect content and configuration of GitHub repos — bundled, opt in by `require` (see [Built-in Features](#built-in-features)) |
|
|
27
|
+
| Changelog | Built-in (changelog/keepachangelog) | Implements [keepachangelog v1.1] — bundled, opt in by `require` (see [Built-in Features](#built-in-features)) |
|
|
28
|
+
| Code Linting | [code_linting-hdi] | Implements a combination of [MegaLinter] and [RuboCop] built on NDRS standards |
|
|
29
|
+
| Code of Conduct | Built-in (code_of_conduct/contributor_covenant) | Implements [Contributor Covenant v2.1] — bundled, opt in by `require` (see [Built-in Features](#built-in-features)) |
|
|
30
|
+
| Decision Records | Built-in (decision_record/madr) | Implements [MADR v3] — bundled, opt in by `require` (see [Built-in Features](#built-in-features)) |
|
|
31
|
+
| Inclusive Language | Built-in (inclusive_language/alex) | Implements [alex] — bundled, opt in by `require` (see [Built-in Features](#built-in-features)) |
|
|
32
|
+
| Pull Request Template | Built-in (pull_request_template/hdi) | Implements a bespoke PR template — bundled, opt in by `require` (see [Built-in Features](#built-in-features)) |
|
|
33
|
+
| Versioning | Built-in (versioning/semver) | Implements [Semantic Versioning v2.0.0] — bundled, opt in by `require` (see [Built-in Features](#built-in-features)) |
|
|
34
|
+
|
|
35
|
+
Some features are **Built-in** — they ship inside this gem and are enabled by requiring them (see [Built-in Features](#built-in-features)); the others are separate plugin gems that you add as dependencies.
|
|
36
|
+
|
|
37
|
+
The standard versions cited above (Contributor Covenant v2.1, MADR v3, and so on) describe the content a feature generates, not the gem's interface. They advance through **minor** releases — see [Versioning Policy](#versioning-policy).
|
|
32
38
|
|
|
33
39
|
## Installation
|
|
34
40
|
|
|
@@ -56,6 +62,161 @@ way_of_working init all --contact-method [CONTACT METHOD]
|
|
|
56
62
|
|
|
57
63
|
You will need to provide the Code of Conduct `[CONTACT METHOD]`, usually an email address, for community leaders to receive reports of unacceptable behavior.
|
|
58
64
|
|
|
65
|
+
### Built-in Features
|
|
66
|
+
|
|
67
|
+
Some features are bundled with this gem rather than shipped as separate plugins. These built-in features are **opt in**: enable one by requiring it wherever you load Way of Working — for example in your organisation's Way of Working gem, or in your project's `Rakefile`.
|
|
68
|
+
|
|
69
|
+
#### Audit
|
|
70
|
+
|
|
71
|
+
Auditing your GitHub repositories against a consistent set of rules catches missing or misconfigured files and repository settings across an organisation, keeping projects aligned with your way of working. Many of the other built-in features register their own rules to check that they have been adopted properly.
|
|
72
|
+
|
|
73
|
+
This feature provides a registry and auditing tool for GitHub repositories; rules can check for both missing/incorrect files and mis-configuration of the repository itself. Enable it by requiring it:
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
require 'way_of_working/audit/github'
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The audit needs two environment variables:
|
|
80
|
+
|
|
81
|
+
- `GITHUB_ORGANISATION`: the name of your organisation being scanned (as used in the GitHub URL)
|
|
82
|
+
- `GITHUB_TOKEN`: a PAT token with sufficient permission to access repositories and their configuration
|
|
83
|
+
|
|
84
|
+
Once required, a subcommand becomes available. By default it runs only against repositories configured as git remotes in your current project:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Audit this project's GitHub repositories
|
|
88
|
+
way_of_working exec audit_github
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Flags let you widen or narrow the scope:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Audit every repository in the organisation
|
|
95
|
+
way_of_working exec audit_github --all
|
|
96
|
+
|
|
97
|
+
# Filter to repositories carrying a topic
|
|
98
|
+
way_of_working exec audit_github --all --topic way-of-working
|
|
99
|
+
|
|
100
|
+
# Audit one or more repositories by name (implies the whole organisation)
|
|
101
|
+
way_of_working exec audit_github --name structured_store other_repo
|
|
102
|
+
|
|
103
|
+
# Audit only public repositories
|
|
104
|
+
way_of_working exec audit_github --all --public
|
|
105
|
+
|
|
106
|
+
# Attempt to automatically fix issues where rules support it
|
|
107
|
+
way_of_working exec audit_github --fix
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### Changelog
|
|
111
|
+
|
|
112
|
+
Keeping a curated, human-readable changelog helps users and contributors quickly see what has changed between releases without trawling through the commit history.
|
|
113
|
+
|
|
114
|
+
This feature uses [Keep a Changelog v1.1][keepachangelog v1.1] to generate a `CHANGELOG.md`, seeding it with sections derived from your git tags and commit messages where possible. Enable it by requiring it:
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
require 'way_of_working/changelog/keepachangelog'
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Once required, a subcommand becomes available:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# Add a Keep a Changelog CHANGELOG.md and documentation to your project
|
|
124
|
+
way_of_working init changelog
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Code of Conduct
|
|
128
|
+
|
|
129
|
+
A code of conduct sets clear expectations for acceptable behaviour within a community or project, helping to create a safer, more welcoming and inclusive environment and giving maintainers a basis for addressing inappropriate behaviour.
|
|
130
|
+
|
|
131
|
+
This feature installs the [Contributor Covenant v2.1] code of conduct along with its accompanying documentation. Enable it by requiring it:
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
require 'way_of_working/code_of_conduct/contributor_covenant'
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Once required, a subcommand becomes available:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# Add the Contributor Covenant code of conduct and documentation to your project
|
|
141
|
+
way_of_working init code_of_conduct --contact-method [CONTACT METHOD]
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
You will need to provide a `[CONTACT METHOD]`, usually an email address, for community leaders to receive reports of unacceptable behavior.
|
|
145
|
+
|
|
146
|
+
#### Decision Records
|
|
147
|
+
|
|
148
|
+
Recording the context and reasoning behind significant decisions helps current and future contributors understand why a project is the way it is, avoids relitigating settled questions, and onboards newcomers faster.
|
|
149
|
+
|
|
150
|
+
This feature uses [Markdown Any Decision Records (MADR)][MADR v3] to capture decisions as version-controlled Markdown alongside your code. Enable it by requiring it:
|
|
151
|
+
|
|
152
|
+
```ruby
|
|
153
|
+
require 'way_of_working/decision_record/madr'
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Once required, two subcommands become available:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Add the decision records index, template and first record to your project
|
|
160
|
+
way_of_working init decision_record
|
|
161
|
+
|
|
162
|
+
# Create a new decision record
|
|
163
|
+
way_of_working new decision_record "Title of the decision"
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### Inclusive Language
|
|
167
|
+
|
|
168
|
+
Using insensitive and inconsiderate language can cause harm to others, create barriers to communication, and damage relationships. It can make people feel excluded, disrespected, and devalued, and may perpetuate negative stereotypes and biases.
|
|
169
|
+
|
|
170
|
+
This feature uses [alex] for automated testing of inclusive language, both at the command line and as a GitHub workflow. Enable it by requiring it:
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
require 'way_of_working/inclusive_language/alex'
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Once required, two subcommands become available:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# Add the alex config, .alexignore, GitHub Action and documentation to your project
|
|
180
|
+
way_of_working init inclusive_language
|
|
181
|
+
|
|
182
|
+
# Run the inclusive language checks
|
|
183
|
+
way_of_working exec inclusive_language
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
#### Pull Request Template
|
|
187
|
+
|
|
188
|
+
A consistent pull request template standardises PR submissions, giving reviewers the context they need, improving review efficiency, and keeping a searchable project history.
|
|
189
|
+
|
|
190
|
+
This feature installs a bespoke HDI pull request template along with its accompanying guidelines documentation. Enable it by requiring it:
|
|
191
|
+
|
|
192
|
+
```ruby
|
|
193
|
+
require 'way_of_working/pull_request_template/hdi'
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Once required, a subcommand becomes available:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# Add the pull request template and documentation to your project
|
|
200
|
+
way_of_working init pull_request_template
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### Versioning
|
|
204
|
+
|
|
205
|
+
A shared versioning standard makes software changes clear to communicate and releases predictable to manage across projects, so consumers can reason about compatibility at a glance.
|
|
206
|
+
|
|
207
|
+
This feature documents [Semantic Versioning v2.0.0] as the project's versioning standard. Enable it by requiring it:
|
|
208
|
+
|
|
209
|
+
```ruby
|
|
210
|
+
require 'way_of_working/versioning/semver'
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Once required, a subcommand becomes available:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
# Add the Semantic Versioning documentation to your project
|
|
217
|
+
way_of_working init versioning
|
|
218
|
+
```
|
|
219
|
+
|
|
59
220
|
### Help
|
|
60
221
|
|
|
61
222
|
More help on using the command line tool is found by using:
|
|
@@ -73,10 +234,26 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
|
73
234
|
|
|
74
235
|
When creating plugins, the convention is to create them within the WayOfWorking and feature namespaces. E.g.
|
|
75
236
|
|
|
237
|
+
### Versioning Policy
|
|
238
|
+
|
|
239
|
+
This project follows [Semantic Versioning][Semantic Versioning v2.0.0], but SemVer governs the gem's **public interface** — the CLI commands and their options, the require paths of built-in features, and the plugin registration API — not the content of the artefacts its generators emit.
|
|
240
|
+
|
|
241
|
+
Consequently:
|
|
242
|
+
|
|
243
|
+
- Refreshing the standard a feature embeds (e.g. a new Contributor Covenant or MADR version) is **new behaviour → MINOR**.
|
|
244
|
+
- A bug fix in generation is **PATCH**.
|
|
245
|
+
- **MAJOR** is reserved for breaking the interface above (renaming or removing a command or option, moving a require path, or changing the plugin API).
|
|
246
|
+
|
|
247
|
+
For a standard update drastic enough to surprise existing users, we add a **new variant** under the feature's `category/variant` namespace rather than mutating the existing one, so both coexist and consumers opt in by require path. This keeps the change additive (MINOR) and leaves existing users untouched.
|
|
248
|
+
|
|
249
|
+
See [ADR-0001](docs/decisions/0001-version-the-gem-interface-not-generated-content.md) for the full rationale and [`CONTRIBUTING.md`](CONTRIBUTING.md) for the version-bump checklist.
|
|
250
|
+
|
|
76
251
|
## Contributing
|
|
77
252
|
|
|
78
253
|
Bug reports and pull requests are welcome on GitHub at <https://github.com/HealthDataInsight/way_of_working>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/HealthDataInsight/way_of_working/blob/main/CODE_OF_CONDUCT.md).
|
|
79
254
|
|
|
255
|
+
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for development setup, the versioning policy and the release process.
|
|
256
|
+
|
|
80
257
|
## License
|
|
81
258
|
|
|
82
259
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
@@ -91,9 +268,5 @@ Everyone interacting in the WayOfWorking project's codebases, issue trackers, ch
|
|
|
91
268
|
[MADR v3]: https://adr.github.io/madr/
|
|
92
269
|
[MegaLinter]: https://megalinter.io/
|
|
93
270
|
[RuboCop]: https://rubocop.org
|
|
94
|
-
[
|
|
271
|
+
[Semantic Versioning v2.0.0]: https://semver.org/spec/v2.0.0.html
|
|
95
272
|
[code_linting-hdi]: https://github.com/HealthDataInsight/way_of_working-code_linting-hdi
|
|
96
|
-
[code_of_conduct-contributor_covenant]: https://github.com/HealthDataInsight/way_of_working-code_of_conduct-contributor_covenant
|
|
97
|
-
[decision_record-madr]: https://github.com/HealthDataInsight/way_of_working-decision_record-madr
|
|
98
|
-
[inclusive_language-alex]: https://github.com/HealthDataInsight/way_of_working-inclusive_language-alex
|
|
99
|
-
[pull_request_template-hdi]: https://github.com/HealthDataInsight/way_of_working-pull_request_template-hdi
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'octokit'
|
|
2
|
+
require_relative 'rules/registry'
|
|
3
|
+
|
|
4
|
+
module WayOfWorking
|
|
5
|
+
module Audit
|
|
6
|
+
module Github
|
|
7
|
+
# This auditor runs all the rules against any given GitHub repository
|
|
8
|
+
class Auditor
|
|
9
|
+
def initialize(access_token, organisation_name, fix = false)
|
|
10
|
+
@access_token = access_token
|
|
11
|
+
@organisation_name = organisation_name
|
|
12
|
+
@fix = fix
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def audit(repository)
|
|
16
|
+
# Get all the rules once, rather than repeatedly in individual rules
|
|
17
|
+
rulesets = @client.get("repos/#{repository.full_name}/rulesets").map do |rule|
|
|
18
|
+
@client.get("repos/#{repository.full_name}/rulesets/#{rule[:id]}")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
Array(Rules::Registry.rules).each do |rule_name, klass|
|
|
22
|
+
rule = klass.new(client, rule_name, repository, rulesets, @fix)
|
|
23
|
+
|
|
24
|
+
yield rule
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def repositories
|
|
29
|
+
@repositories ||= client.org_repos(@organisation_name)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def client
|
|
35
|
+
@client ||= begin
|
|
36
|
+
client = Octokit::Client.new(access_token: @access_token) # , per_page: 1_000
|
|
37
|
+
client.auto_paginate = true
|
|
38
|
+
client
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'git'
|
|
4
|
+
require 'rainbow'
|
|
5
|
+
require 'thor'
|
|
6
|
+
require 'way_of_working/audit/github/auditor'
|
|
7
|
+
# require 'way_of_working/github_audit/rules/all'
|
|
8
|
+
|
|
9
|
+
module WayOfWorking
|
|
10
|
+
module Audit
|
|
11
|
+
module Github
|
|
12
|
+
module Generators
|
|
13
|
+
# This generator runs the github audit
|
|
14
|
+
class Exec < Thor::Group
|
|
15
|
+
class_option :all, type: :boolean, default: false,
|
|
16
|
+
desc: 'Audit all repositories in the organisation (not just this repo)'
|
|
17
|
+
|
|
18
|
+
class_option :fix, type: :boolean, default: false,
|
|
19
|
+
desc: 'Attempt to automatically fix issues where possible'
|
|
20
|
+
|
|
21
|
+
class_option :name, type: :array, default: nil,
|
|
22
|
+
desc: 'Filter repositories by name (e.g., structured_store)'
|
|
23
|
+
|
|
24
|
+
class_option :public, type: :boolean, default: false,
|
|
25
|
+
desc: 'Filter to only public repositories'
|
|
26
|
+
|
|
27
|
+
class_option :topic, type: :string, default: nil,
|
|
28
|
+
desc: 'Filter repositories by topic (e.g., way-of-working)'
|
|
29
|
+
|
|
30
|
+
desc 'This runs the github audit on this project'
|
|
31
|
+
|
|
32
|
+
def check_for_github_token_environment_variables
|
|
33
|
+
@github_token = ENV.fetch('GITHUB_TOKEN', nil)
|
|
34
|
+
return unless @github_token.nil?
|
|
35
|
+
|
|
36
|
+
abort(Rainbow("\nMissing GITHUB_TOKEN environment variable").red)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def check_for_github_organisation_environment_variables
|
|
40
|
+
@github_organisation = ENV.fetch('GITHUB_ORGANISATION', nil)
|
|
41
|
+
return unless @github_organisation.nil?
|
|
42
|
+
|
|
43
|
+
abort(Rainbow("\nMissing GITHUB_ORGANISATION environment variable").red)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def start_timer
|
|
47
|
+
@start_time = Time.now
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def check_github_organisation_remotes
|
|
51
|
+
abort(Rainbow("\nGitHub is not an upstream repository.").red) if github_organisation_remotes.empty?
|
|
52
|
+
|
|
53
|
+
# say("Limiting audit to #{path}\n", :yellow) if path
|
|
54
|
+
say "\nRunning..."
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def prep_audit
|
|
58
|
+
@auditor = ::WayOfWorking::Audit::Github::Auditor.new(@github_token, @github_organisation, options[:fix])
|
|
59
|
+
|
|
60
|
+
# Loop though all the repos
|
|
61
|
+
@repositories = @auditor.repositories
|
|
62
|
+
rescue Octokit::Unauthorized
|
|
63
|
+
abort(Rainbow("\nGITHUB_TOKEN has expired or does not have sufficient permission").red)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def filter_all_if_specified
|
|
67
|
+
return if options[:all] || options[:name]
|
|
68
|
+
|
|
69
|
+
@repositories = @repositories.select do |repo|
|
|
70
|
+
github_organisation_remotes.include?(repo.name)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def filter_by_name_array_if_specified
|
|
75
|
+
return unless options[:name]
|
|
76
|
+
|
|
77
|
+
@repositories = @repositories.select do |repo|
|
|
78
|
+
options[:name].include?(repo.name)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def filter_by_topic_if_specified
|
|
83
|
+
return unless options[:topic]
|
|
84
|
+
|
|
85
|
+
@repositories = @repositories.select do |repo|
|
|
86
|
+
repo.topics.include?(options[:topic])
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def filter_by_visibility_if_specified
|
|
91
|
+
return unless options[:public]
|
|
92
|
+
|
|
93
|
+
@repositories = @repositories.reject(&:private?)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def run_audit
|
|
97
|
+
@audit_ok = true
|
|
98
|
+
unarchived_repos.each do |repo|
|
|
99
|
+
@auditor.audit(repo) do |rule|
|
|
100
|
+
case rule.status
|
|
101
|
+
when :not_applicable
|
|
102
|
+
# Do nothing
|
|
103
|
+
when :passed
|
|
104
|
+
say " ✅ #{rule.tags.inspect} Passed #{rule.name}"
|
|
105
|
+
when :failed
|
|
106
|
+
say " ❌ #{rule.tags.inspect} Failed #{rule.name}: #{rule.errors.to_sentence}"
|
|
107
|
+
@audit_ok = false
|
|
108
|
+
else
|
|
109
|
+
abort(Rainbow("Unknown response #{rule.status.inspect}").red)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def run_last
|
|
116
|
+
say("\nTotal time taken: #{(Time.now - @start_time).to_i} seconds", :yellow)
|
|
117
|
+
|
|
118
|
+
if @audit_ok
|
|
119
|
+
say("\nGitHub audit succeeded!", :green)
|
|
120
|
+
else
|
|
121
|
+
abort(Rainbow("\nGitHub audit failed!").red)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
def unarchived_repos(&block)
|
|
128
|
+
return to_enum(__method__) unless block_given?
|
|
129
|
+
|
|
130
|
+
@repositories.each do |repo|
|
|
131
|
+
next if repo.archived?
|
|
132
|
+
|
|
133
|
+
say
|
|
134
|
+
say("#{repo.name} #{repo.private? ? '🔒' : ''}", :bold)
|
|
135
|
+
say("#{repo.description} [#{repo.language}]")
|
|
136
|
+
say(repo.topics.join(' '), :cyan) unless repo.topics.empty?
|
|
137
|
+
|
|
138
|
+
block.call(repo)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# This method returns the repo names for all upstream repositories
|
|
143
|
+
# hosted on GitHub, for the given organisation
|
|
144
|
+
def github_organisation_remotes
|
|
145
|
+
@github_organisation_remotes ||= begin
|
|
146
|
+
all_remote_urls = ::Git.open('.').remotes.map(&:url)
|
|
147
|
+
|
|
148
|
+
organisation_remote_urls = all_remote_urls.select do |url|
|
|
149
|
+
url.start_with?("https://github.com/#{@github_organisation}")
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
organisation_remote_urls.map do |url|
|
|
153
|
+
matchdata = url.match(%r{\Ahttps://github.com/([^/]+)/([^/]+)\.git})
|
|
154
|
+
|
|
155
|
+
matchdata[2]
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support'
|
|
4
|
+
require 'active_support/core_ext'
|
|
5
|
+
require 'base64'
|
|
6
|
+
require 'octokit'
|
|
7
|
+
require_relative 'registry'
|
|
8
|
+
|
|
9
|
+
module WayOfWorking
|
|
10
|
+
module Audit
|
|
11
|
+
module Github
|
|
12
|
+
module Rules
|
|
13
|
+
# This is the base class for GitHub audit rules
|
|
14
|
+
class Base
|
|
15
|
+
attr_accessor :errors, :name, :rulesets, :warnings
|
|
16
|
+
attr_reader :fix
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
# Stores and return the source root for this class
|
|
20
|
+
def source_root(path = nil)
|
|
21
|
+
@source_root = path if path
|
|
22
|
+
@source_root ||= nil
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def initialize(client, name, repo, rulesets, fix = false)
|
|
27
|
+
@client = client
|
|
28
|
+
@name = name
|
|
29
|
+
@repo = repo
|
|
30
|
+
@repo_name = repo.full_name
|
|
31
|
+
@rulesets = rulesets
|
|
32
|
+
@fix = fix
|
|
33
|
+
@errors = []
|
|
34
|
+
@warnings = []
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def status
|
|
38
|
+
@status ||= begin
|
|
39
|
+
result = validate
|
|
40
|
+
|
|
41
|
+
if result == :not_applicable
|
|
42
|
+
result
|
|
43
|
+
else
|
|
44
|
+
@errors.empty? ? :passed : :failed
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def validate
|
|
50
|
+
$stdout.puts "Rule#valid? has been deprecated, use \"validate\" in #{self.class.name}"
|
|
51
|
+
valid?
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.tags
|
|
55
|
+
[:way_of_working]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def tags
|
|
59
|
+
self.class.tags
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def repo_file_contents(path)
|
|
65
|
+
response = @client.contents(@repo_name, path: path)
|
|
66
|
+
Base64.decode64(response.content).force_encoding('UTF-8')
|
|
67
|
+
rescue Octokit::NotFound
|
|
68
|
+
nil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# This method returns the content of the README file
|
|
72
|
+
def readme_content
|
|
73
|
+
@readme_content ||=
|
|
74
|
+
begin
|
|
75
|
+
response = @client.readme(@repo_name)
|
|
76
|
+
|
|
77
|
+
Base64.decode64(response.content).force_encoding('UTF-8')
|
|
78
|
+
rescue Octokit::NotFound
|
|
79
|
+
''
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# This convenience method returns the branch rules for this repo
|
|
84
|
+
def branch_rules(branch)
|
|
85
|
+
@client.get("repos/#{@repo.full_name}/rules/branches/#{branch}")
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|