gh-formatter 0.1.0__tar.gz

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.
Files changed (61) hide show
  1. gh_formatter-0.1.0/.gh-formatter.yml +229 -0
  2. gh_formatter-0.1.0/.github/CODEOWNERS +10 -0
  3. gh_formatter-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +91 -0
  4. gh_formatter-0.1.0/.github/ISSUE_TEMPLATE/config.yml +7 -0
  5. gh_formatter-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +50 -0
  6. gh_formatter-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +33 -0
  7. gh_formatter-0.1.0/.github/dependabot.yml +36 -0
  8. gh_formatter-0.1.0/.github/rulesets/README.md +50 -0
  9. gh_formatter-0.1.0/.github/workflows/build_and_test.yml +82 -0
  10. gh_formatter-0.1.0/.github/workflows/release.yml +105 -0
  11. gh_formatter-0.1.0/.gitignore +218 -0
  12. gh_formatter-0.1.0/.pre-commit-config.yaml +47 -0
  13. gh_formatter-0.1.0/.pre-commit-hooks.yaml +8 -0
  14. gh_formatter-0.1.0/.yamllint.yml +34 -0
  15. gh_formatter-0.1.0/CODE_OF_CONDUCT.md +60 -0
  16. gh_formatter-0.1.0/CONTRIBUTING.md +144 -0
  17. gh_formatter-0.1.0/LICENSE +21 -0
  18. gh_formatter-0.1.0/PKG-INFO +501 -0
  19. gh_formatter-0.1.0/README.md +468 -0
  20. gh_formatter-0.1.0/SECURITY.md +24 -0
  21. gh_formatter-0.1.0/examples/caller_workflow_example.yml +55 -0
  22. gh_formatter-0.1.0/examples/codeql.yml +59 -0
  23. gh_formatter-0.1.0/examples/composite_action/action.yml +57 -0
  24. gh_formatter-0.1.0/examples/docker-publish.yml +99 -0
  25. gh_formatter-0.1.0/examples/reusable_workflow_example.yml +72 -0
  26. gh_formatter-0.1.0/examples/workflow_example.yml +160 -0
  27. gh_formatter-0.1.0/pyproject.toml +122 -0
  28. gh_formatter-0.1.0/src/gh_formatter/__init__.py +2 -0
  29. gh_formatter-0.1.0/src/gh_formatter/casing.py +80 -0
  30. gh_formatter-0.1.0/src/gh_formatter/cli.py +289 -0
  31. gh_formatter-0.1.0/src/gh_formatter/comments.py +358 -0
  32. gh_formatter-0.1.0/src/gh_formatter/config.py +341 -0
  33. gh_formatter-0.1.0/src/gh_formatter/context.py +89 -0
  34. gh_formatter-0.1.0/src/gh_formatter/directives.py +110 -0
  35. gh_formatter-0.1.0/src/gh_formatter/discovery.py +62 -0
  36. gh_formatter-0.1.0/src/gh_formatter/engine.py +108 -0
  37. gh_formatter-0.1.0/src/gh_formatter/postprocess.py +184 -0
  38. gh_formatter-0.1.0/src/gh_formatter/project.py +109 -0
  39. gh_formatter-0.1.0/src/gh_formatter/references.py +60 -0
  40. gh_formatter-0.1.0/src/gh_formatter/rules/__init__.py +27 -0
  41. gh_formatter-0.1.0/src/gh_formatter/rules/alphabetize.py +58 -0
  42. gh_formatter-0.1.0/src/gh_formatter/rules/base.py +29 -0
  43. gh_formatter-0.1.0/src/gh_formatter/rules/callers.py +157 -0
  44. gh_formatter-0.1.0/src/gh_formatter/rules/if_expressions.py +68 -0
  45. gh_formatter-0.1.0/src/gh_formatter/rules/inputs.py +130 -0
  46. gh_formatter-0.1.0/src/gh_formatter/rules/jobs.py +84 -0
  47. gh_formatter-0.1.0/src/gh_formatter/rules/keys.py +137 -0
  48. gh_formatter-0.1.0/src/gh_formatter/rules/lists.py +73 -0
  49. gh_formatter-0.1.0/src/gh_formatter/rules/names.py +63 -0
  50. gh_formatter-0.1.0/src/gh_formatter/rules/quotes.py +51 -0
  51. gh_formatter-0.1.0/src/gh_formatter/rules/style.py +57 -0
  52. gh_formatter-0.1.0/src/gh_formatter/utils.py +133 -0
  53. gh_formatter-0.1.0/src/gh_formatter/yamllint_sync.py +78 -0
  54. gh_formatter-0.1.0/tests/__init__.py +1 -0
  55. gh_formatter-0.1.0/tests/test_casing.py +36 -0
  56. gh_formatter-0.1.0/tests/test_cli.py +105 -0
  57. gh_formatter-0.1.0/tests/test_config.py +140 -0
  58. gh_formatter-0.1.0/tests/test_cross_file.py +418 -0
  59. gh_formatter-0.1.0/tests/test_directives.py +139 -0
  60. gh_formatter-0.1.0/tests/test_regressions.py +465 -0
  61. gh_formatter-0.1.0/tests/test_rules.py +357 -0
@@ -0,0 +1,229 @@
1
+ # Comprehensive Configuration for gh-formatter
2
+ # =============================================
3
+ # This file controls all formatting options for GitHub Actions and Workflows.
4
+ # All settings shown below are optional and use the defaults listed.
5
+
6
+ # INDENTATION SETTINGS
7
+ # ====================
8
+
9
+ # Number of spaces to use for general indentation (default: 2)
10
+ # Recommended values: 2 or 4
11
+ indent: 2
12
+
13
+ # Number of spaces to indent sequence (list) item content (default: 4)
14
+ # Must be greater than sequence_offset.
15
+ sequence_indent: 4
16
+
17
+ # Indentation of the dash in sequence items (default: 2)
18
+ # Controls how far the `-` is indented relative to its parent key.
19
+ # Example with sequence_offset: 2 (default), sequence_indent: 4:
20
+ # steps:
21
+ # - name: item1
22
+ # - name: item2
23
+ # Example with sequence_offset: 0, sequence_indent: 2:
24
+ # steps:
25
+ # - name: item1
26
+ # - name: item2
27
+ sequence_offset: 2
28
+
29
+
30
+ # NAMING CONVENTIONS
31
+ # ==================
32
+
33
+ # Casing convention for input names in actions and workflows
34
+ # Options: "dash-case" or "snake_case"
35
+ # Examples:
36
+ # dash-case: my-input, debug-mode, run-tests
37
+ # snake_case: my_input, debug_mode, run_tests
38
+ # Default: "dash-case"
39
+ input_casing: "dash-case"
40
+
41
+ # Casing convention for job names in workflows
42
+ # Options: "snake_case" or "dash-case"
43
+ # Examples:
44
+ # snake_case: build_job, run_tests, deploy_app
45
+ # dash-case: build-job, run-tests, deploy-app
46
+ # Default: "snake_case"
47
+ job_casing: "snake_case"
48
+
49
+ # How to treat env-var style names (SERVER_IMAGE, MM_ENV) when renaming
50
+ # inputs and jobs:
51
+ # false (default): renamed to the configured casing like any other name
52
+ # true: kept uppercase, separators normalized to underscores
53
+ # (SERVER-IMAGE becomes SERVER_IMAGE)
54
+ preserve_uppercase_names: false
55
+
56
+ # Line endings for formatted files
57
+ # Options: "preserve" (keep each file's existing endings) or "lf" (Unix)
58
+ # Default: "preserve"
59
+ line_endings: "preserve"
60
+
61
+
62
+ # QUOTE STYLE
63
+ # ===========
64
+
65
+ # Quote character to enforce on already-quoted scalars.
66
+ # Options: "double", "single", or "preserve"
67
+ # double: normalize every quoted scalar to "..." (default)
68
+ # single: normalize every quoted scalar to '...'
69
+ # preserve: leave each scalar's existing quoting untouched
70
+ # Plain (unquoted) values are never force-quoted, and ruamel falls back
71
+ # to double quoting when a value cannot be single-quoted safely.
72
+ quote_style: "double"
73
+
74
+
75
+ # YAMLLINT INTEROP
76
+ # ================
77
+
78
+ # Make a yamllint config the source of truth for indentation so a format
79
+ # never produces output yamllint would reject. Requires yamllint installed.
80
+ # Options:
81
+ # false (default): ignore yamllint, use the indentation settings above
82
+ # true: discover .yamllint(.yml/.yaml) in the working directory
83
+ # <path>: read indentation from that explicit yamllint config
84
+ # When enabled, the derived indent/sequence settings override the ones above.
85
+ defer_to_yamllint: false
86
+
87
+
88
+ # CALLER INPUTS
89
+ # =============
90
+
91
+ # How to handle a caller's with: keys that don't match a LOCAL reusable
92
+ # workflow/action's declared inputs (uses: ./...). Marketplace actions are
93
+ # never checked.
94
+ # Options:
95
+ # "error" (default): report the mismatch as an error and fail the run
96
+ # "fix": rename the caller's keys to match (at your own risk)
97
+ # "ignore": leave caller inputs alone
98
+ caller_inputs: "error"
99
+
100
+
101
+ # ALPHABETICAL SORTING
102
+ # ====================
103
+
104
+ # Mapping blocks whose entries are sorted alphabetically (case-insensitive).
105
+ # Entry order in these blocks never carries meaning, so sorting them makes
106
+ # diffs and reviews predictable. Set to [] to disable sorting entirely, or
107
+ # add further block names (e.g. "permissions").
108
+ alphabetize:
109
+ - env
110
+ - inputs
111
+ - outputs
112
+ - secrets
113
+ - with
114
+
115
+
116
+ # LIST FORMATTING STYLE
117
+ # =====================
118
+
119
+ # How to format trigger filter lists under `on:` (branches, tags, paths, ...)
120
+ # Options: "flow" or "block"
121
+ # flow: [item1, item2, item3]
122
+ # block: - item1
123
+ # - item2
124
+ # - item3
125
+ # Default: "block"
126
+ list_style: "block"
127
+
128
+ # Which keys under `on:` are treated as filter lists. Single string values
129
+ # are promoted to lists and the configured list_style is applied.
130
+ # Default shown below.
131
+ list_keys:
132
+ - branches
133
+ - branches-ignore
134
+ - tags
135
+ - tags-ignore
136
+ - paths
137
+ - paths-ignore
138
+ - types
139
+ - workflows
140
+
141
+
142
+ # BLANK LINES
143
+ # ===========
144
+
145
+ # Insert a blank line between consecutive steps (default: true)
146
+ blank_line_between_steps: true
147
+
148
+ # Insert a blank line between job definitions (default: true)
149
+ blank_line_between_jobs: true
150
+
151
+
152
+ # RULE TOGGLES
153
+ # ============
154
+
155
+ # Disable individual rules or post-processors by id.
156
+ # Run `gh-formatter --list-rules` to see all available ids.
157
+ # All rules are enabled by default.
158
+ rules: {}
159
+ # Example:
160
+ # rules:
161
+ # capitalize-names: false
162
+ # blank-lines: false
163
+
164
+
165
+ # KEY ORDERING
166
+ # ============
167
+
168
+ # Order of keys for GitHub Actions workflow files (.github/workflows/*.yml)
169
+ # Keys not listed here will be placed at the end in alphabetical order
170
+ # Default order shown below (recommended for readability)
171
+ key_order_workflow:
172
+ - name
173
+ - run-name
174
+ - "on" # quoted so YAML 1.1 linters don't read it as the boolean true
175
+ - concurrency
176
+ - permissions
177
+ - env
178
+ - defaults
179
+ - jobs
180
+
181
+ # Order of keys for GitHub Actions definition files (action.yml / action.yaml)
182
+ # Keys not listed here will be placed at the end in alphabetical order
183
+ # Default order shown below (recommended for readability)
184
+ key_order_action:
185
+ - name
186
+ - description
187
+ - author
188
+ - inputs
189
+ - outputs
190
+ - runs
191
+ - branding
192
+
193
+ # Order of keys inside each job definition
194
+ # Default order shown below
195
+ key_order_job:
196
+ - name
197
+ - if
198
+ - needs
199
+ - runs-on
200
+ - env
201
+ - uses
202
+ - with
203
+ - secrets
204
+ - permissions
205
+ - environment
206
+ - concurrency
207
+ - strategy
208
+ - container
209
+ - services
210
+ - outputs
211
+ - defaults
212
+ - timeout-minutes
213
+ - continue-on-error
214
+ - steps
215
+
216
+ # Order of keys inside each step
217
+ # Default order shown below
218
+ key_order_step:
219
+ - name
220
+ - id
221
+ - if
222
+ - env
223
+ - uses
224
+ - continue-on-error
225
+ - run
226
+ - with
227
+ - working-directory
228
+ - shell
229
+ - timeout-minutes
@@ -0,0 +1,10 @@
1
+ # Code owners for gh-formatter
2
+ #
3
+ # The owner(s) listed here are automatically requested for review on every PR
4
+ # and — combined with the "Require review from Code Owners" branch ruleset —
5
+ # are the ONLY accounts whose approval can satisfy the required review.
6
+ #
7
+ # Keep this list to the repository admin(s) only. Anyone added here who also
8
+ # has Write access can approve & merge, so do not add external contributors.
9
+
10
+ * @nimpsch
@@ -0,0 +1,91 @@
1
+ name: Bug report
2
+ description: Report incorrect or unexpected formatting behavior
3
+ title: "[Bug]: "
4
+ labels: ["bug"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for taking the time to report a bug! A minimal reproduction
10
+ makes fixing it dramatically faster.
11
+
12
+ - type: textarea
13
+ id: what-happened
14
+ attributes:
15
+ label: What happened?
16
+ description: A clear description of the bug.
17
+ placeholder: gh-formatter changed X into Y, but it should have ...
18
+ validations:
19
+ required: true
20
+
21
+ - type: textarea
22
+ id: input-yaml
23
+ attributes:
24
+ label: Input YAML
25
+ description: >
26
+ The smallest workflow/action snippet that reproduces the problem.
27
+ This will be rendered as YAML, no backticks needed.
28
+ render: yaml
29
+ placeholder: |
30
+ name: ci
31
+ on: push
32
+ jobs:
33
+ build:
34
+ runs-on: ubuntu-latest
35
+ validations:
36
+ required: true
37
+
38
+ - type: textarea
39
+ id: command
40
+ attributes:
41
+ label: Command
42
+ description: The exact command you ran.
43
+ render: shell
44
+ placeholder: gh-formatter .github/workflows/ci.yml
45
+ validations:
46
+ required: true
47
+
48
+ - type: textarea
49
+ id: expected
50
+ attributes:
51
+ label: Expected output
52
+ description: What you expected gh-formatter to produce.
53
+ render: yaml
54
+ validations:
55
+ required: true
56
+
57
+ - type: textarea
58
+ id: actual
59
+ attributes:
60
+ label: Actual output
61
+ description: What gh-formatter actually produced.
62
+ render: yaml
63
+ validations:
64
+ required: true
65
+
66
+ - type: textarea
67
+ id: config
68
+ attributes:
69
+ label: Configuration
70
+ description: >
71
+ Your `.gh-formatter.yml` / `[tool.gh-formatter]` config, if any.
72
+ render: yaml
73
+ validations:
74
+ required: false
75
+
76
+ - type: input
77
+ id: version
78
+ attributes:
79
+ label: gh-formatter version
80
+ description: Output of `pip show gh-formatter` (the Version line).
81
+ placeholder: 0.1.0
82
+ validations:
83
+ required: true
84
+
85
+ - type: input
86
+ id: python-version
87
+ attributes:
88
+ label: Python version
89
+ placeholder: "3.12"
90
+ validations:
91
+ required: true
@@ -0,0 +1,7 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Question or discussion
4
+ url: https://github.com/nimpsch/gh-formatter/discussions
5
+ about: >
6
+ Ask a question or discuss an idea. For bugs and concrete feature
7
+ requests, please use the issue templates instead.
@@ -0,0 +1,50 @@
1
+ name: Feature request
2
+ description: Suggest a new rule, option, or improvement
3
+ title: "[Feature]: "
4
+ labels: ["enhancement"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for suggesting an improvement! Please describe the problem you
10
+ are trying to solve, not only the solution you have in mind.
11
+
12
+ - type: textarea
13
+ id: problem
14
+ attributes:
15
+ label: Problem / motivation
16
+ description: What are you trying to achieve? What is painful today?
17
+ placeholder: >
18
+ When formatting reusable workflows, I want ... because ...
19
+ validations:
20
+ required: true
21
+
22
+ - type: textarea
23
+ id: proposal
24
+ attributes:
25
+ label: Proposed solution
26
+ description: >
27
+ How might this work? If it is a new formatting rule or option,
28
+ show a before/after example.
29
+ render: yaml
30
+ validations:
31
+ required: true
32
+
33
+ - type: textarea
34
+ id: alternatives
35
+ attributes:
36
+ label: Alternatives considered
37
+ description: Other approaches you thought about, and why you ruled them out.
38
+ validations:
39
+ required: false
40
+
41
+ - type: dropdown
42
+ id: contribute
43
+ attributes:
44
+ label: Would you be willing to contribute this?
45
+ options:
46
+ - "Yes, I'd like to open a PR"
47
+ - "Maybe, with some guidance"
48
+ - "No, just suggesting"
49
+ validations:
50
+ required: false
@@ -0,0 +1,33 @@
1
+ <!--
2
+ Thanks for contributing! Please keep PRs focused on one logical change.
3
+ The title becomes the squashed commit subject — make it descriptive and
4
+ write it in the imperative ("Add ...", "Fix ...").
5
+ -->
6
+
7
+ ## What does this PR do?
8
+
9
+ <!-- A short description of the change. -->
10
+
11
+ ## Why?
12
+
13
+ <!-- The motivation / the problem this solves. Link the issue if there is one. -->
14
+
15
+ Fixes #
16
+
17
+ ## How was it tested?
18
+
19
+ <!--
20
+ Describe the tests you added and/or the manual verification you did.
21
+ For formatting changes, a before/after YAML example is very helpful.
22
+ -->
23
+
24
+ ## Checklist
25
+
26
+ <!--
27
+ No need to tick off formatting, linting, type-checking, or test runs:
28
+ CI runs black, ruff, mypy, pytest, and yamllint (via pre-commit) on every PR.
29
+ -->
30
+
31
+ - [ ] Tests added or updated (bug fixes include a regression test)
32
+ - [ ] Docs updated (README / `.gh-formatter.yml`) if behavior or options changed
33
+ - [ ] This PR is one focused change
@@ -0,0 +1,36 @@
1
+ version: 2
2
+ updates:
3
+ # Python packages declared in pyproject.toml.
4
+ - package-ecosystem: pip
5
+ directory: /
6
+ schedule:
7
+ interval: weekly
8
+ # Bump the declared requirement itself (not just a lockfile) so update
9
+ # PRs are still raised for ">=" requirements. Note: for a package that
10
+ # is published to PyPI, Dependabot treats it as a library and may leave
11
+ # an unbounded ">=" requirement alone when the newest release already
12
+ # satisfies it -- add an upper bound (e.g. ">=1,<2") if you want those.
13
+ versioning-strategy: increase
14
+ groups:
15
+ python-dependencies:
16
+ patterns:
17
+ - "*"
18
+
19
+ - package-ecosystem: github-actions
20
+ directory: /
21
+ schedule:
22
+ interval: weekly
23
+ groups:
24
+ github-actions:
25
+ patterns:
26
+ - "*"
27
+
28
+ # Bumps the `rev:` of each hook in .pre-commit-config.yaml.
29
+ - package-ecosystem: pre-commit
30
+ directory: /
31
+ schedule:
32
+ interval: weekly
33
+ groups:
34
+ pre-commit:
35
+ patterns:
36
+ - "*"
@@ -0,0 +1,50 @@
1
+ # Repository rulesets
2
+
3
+ These JSON files are importable [repository rulesets](https://docs.github.com/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/managing-rulesets-for-a-repository).
4
+ They are kept in the repo for version control; GitHub does **not** apply them
5
+ automatically — you must import them once (and re-import after edits).
6
+
7
+ ## How to import
8
+
9
+ 1. Go to **Settings → Rules → Rulesets** in the repository.
10
+ 2. Click **New ruleset → Import a ruleset**.
11
+ 3. Select the JSON file and click **Create**.
12
+ 4. Repeat for each file.
13
+
14
+ ## Files
15
+
16
+ | File | What it does |
17
+ | ---- | ------------ |
18
+ | `main-branch-protection.json` | Protects the default branch: requires a PR with 1 Code Owner approval, passing CI, linear history, blocks force-push and deletion. |
19
+ | `branch-naming.json` | Enforces a naming convention on all non-default branches pushed to this repo. |
20
+
21
+ ## Who can approve & merge
22
+
23
+ - **Approve:** Only accounts in [`.github/CODEOWNERS`](../CODEOWNERS) that also have
24
+ Write+ access satisfy the required review. Today that is only `@nimpsch`.
25
+ External contributors fork the repo and have read-only access, so their reviews
26
+ are non-binding.
27
+ - **Merge:** Only accounts with Write+ access can click merge. On a public repo,
28
+ forkers never have write, so they can never merge. Keep yourself the sole
29
+ admin/collaborator and you remain the only person who can merge.
30
+
31
+ The default-branch ruleset lists **Repository admin (`actor_id: 5`)** as a bypass
32
+ actor so you can merge your own PRs (a PR author cannot approve their own PR).
33
+ Remove the `bypass_actors` entry if you want the review requirement to apply to
34
+ you as well.
35
+
36
+ ## Branch naming convention
37
+
38
+ Non-default branches must match:
39
+
40
+ ```
41
+ ^(feature|fix|hotfix|chore|docs|refactor|test|ci|build|perf|release|dependabot)/[a-z0-9._/-]+$
42
+ ```
43
+
44
+ Examples that pass: `feature/yaml-anchors`, `fix/issue-42`, `docs/readme-badges`,
45
+ `dependabot/pip/black-25.1.0`.
46
+
47
+ > **Note:** Branch-name rules apply only to branches created in *this* repo.
48
+ > A fork is a separate repository, so this rule cannot constrain the head-branch
49
+ > name of a PR opened from someone else's fork — it governs your own branches and
50
+ > any direct collaborators.
@@ -0,0 +1,82 @@
1
+ name: Build and Test
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - main
10
+ workflow_dispatch:
11
+
12
+ jobs:
13
+ test:
14
+ name: Test on Python ${{ matrix.python-version }}
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ python-version:
20
+ - "3.11"
21
+ - "3.12"
22
+ - "3.13"
23
+ - "3.14"
24
+
25
+ steps:
26
+ - name: Checkout code
27
+ uses: actions/checkout@v6
28
+
29
+ - name: Set up Python
30
+ uses: actions/setup-python@v6
31
+ with:
32
+ python-version: ${{ matrix.python-version }}
33
+
34
+ - name: Install package with dev dependencies
35
+ run: |
36
+ python -m pip install --upgrade pip
37
+ pip install -e ".[dev]"
38
+
39
+ - name: Run tests
40
+ run: pytest
41
+
42
+ lint:
43
+ name: Lint and type-check
44
+ runs-on: ubuntu-latest
45
+ steps:
46
+ - name: Checkout code
47
+ uses: actions/checkout@v6
48
+
49
+ - name: Set up Python
50
+ uses: actions/setup-python@v6
51
+ with:
52
+ python-version: "3.12"
53
+
54
+ # gh-formatter must be importable for its (system) pre-commit hook;
55
+ # pre-commit manages the envs for black, ruff, mypy, and yamllint.
56
+ - name: Install package and pre-commit
57
+ run: |
58
+ python -m pip install --upgrade pip
59
+ pip install -e ".[dev]" pre-commit
60
+
61
+ # Single entry point: black, ruff, mypy, the gh-formatter self-check,
62
+ # and yamllint all run through pre-commit (see .pre-commit-config.yaml).
63
+ - name: Run pre-commit
64
+ run: pre-commit run --all-files --show-diff-on-failure
65
+
66
+ build:
67
+ name: Verify package builds
68
+ runs-on: ubuntu-latest
69
+ steps:
70
+ - name: Checkout code
71
+ uses: actions/checkout@v6
72
+
73
+ - name: Set up Python
74
+ uses: actions/setup-python@v6
75
+ with:
76
+ python-version: "3.12"
77
+
78
+ - name: Build sdist and wheel
79
+ run: |
80
+ python -m pip install --upgrade pip build twine
81
+ python -m build
82
+ twine check dist/*
@@ -0,0 +1,105 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ test:
10
+ name: Run linting and tests
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - name: Checkout code
14
+ uses: actions/checkout@v6
15
+
16
+ - name: Set up Python
17
+ uses: actions/setup-python@v6
18
+ with:
19
+ python-version: "3.12"
20
+
21
+ - name: Install package with dev dependencies
22
+ run: |
23
+ python -m pip install --upgrade pip
24
+ pip install -e ".[dev]"
25
+
26
+ - name: Check formatting
27
+ run: gh-formatter --check .
28
+
29
+ - name: Run tests
30
+ run: pytest
31
+
32
+ build:
33
+ name: Build distribution
34
+ needs: test
35
+ runs-on: ubuntu-latest
36
+ steps:
37
+ - name: Checkout code
38
+ uses: actions/checkout@v6
39
+
40
+ - name: Set up Python
41
+ uses: actions/setup-python@v6
42
+ with:
43
+ python-version: "3.12"
44
+
45
+ - name: Verify tag matches package version
46
+ run: |
47
+ TAG_VERSION="${GITHUB_REF_NAME#v}"
48
+ PKG_VERSION="$(python -c "import re, pathlib; print(re.search(r'__version__ = \"(.+?)\"', pathlib.Path('src/gh_formatter/__init__.py').read_text()).group(1))")"
49
+ if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
50
+ echo "Tag version ($TAG_VERSION) does not match package version ($PKG_VERSION)" >&2
51
+ exit 1
52
+ fi
53
+
54
+ - name: Install build tooling
55
+ run: python -m pip install --upgrade pip build twine
56
+
57
+ - name: Build sdist and wheel
58
+ run: python -m build
59
+
60
+ - name: Check distribution metadata
61
+ run: twine check dist/*
62
+
63
+ - name: Upload distribution artifacts
64
+ uses: actions/upload-artifact@v7
65
+ with:
66
+ name: dist
67
+ path: dist/
68
+
69
+ publish:
70
+ name: Publish to PyPI
71
+ needs: build
72
+ runs-on: ubuntu-latest
73
+ permissions: # Required for PyPI Trusted Publishing (OIDC)
74
+ id-token: write
75
+ environment:
76
+ name: pypi
77
+ url: https://pypi.org/p/gh-formatter
78
+ steps:
79
+ - name: Download distribution artifacts
80
+ uses: actions/download-artifact@v8
81
+ with:
82
+ name: dist
83
+ path: dist/
84
+
85
+ - name: Publish to PyPI
86
+ uses: pypa/gh-action-pypi-publish@release/v1
87
+
88
+ github_release:
89
+ name: Create GitHub release
90
+ needs: publish
91
+ runs-on: ubuntu-latest
92
+ permissions:
93
+ contents: write
94
+ steps:
95
+ - name: Download distribution artifacts
96
+ uses: actions/download-artifact@v8
97
+ with:
98
+ name: dist
99
+ path: dist/
100
+
101
+ - name: Create release with artifacts
102
+ uses: softprops/action-gh-release@v3
103
+ with:
104
+ files: dist/*
105
+ generate_release_notes: true