bitwarden_workflow_linter 0.0.3__tar.gz → 0.0.4__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 (74) hide show
  1. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/.github/CODEOWNERS +1 -1
  2. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/.github/renovate.json +1 -0
  3. bitwarden_workflow_linter-0.0.4/.github/workflows/_version_type.yml +57 -0
  4. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/.github/workflows/cd.yml +35 -48
  5. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/.github/workflows/ci.yml +2 -2
  6. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/.github/workflows/enforce-labels.yml +1 -2
  7. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/.github/workflows/scan.yml +5 -5
  8. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/.gitignore +5 -0
  9. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/PKG-INFO +5 -1
  10. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/README.md +4 -0
  11. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/package-lock.json +8 -8
  12. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/package.json +2 -2
  13. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/settings.yaml +1 -0
  14. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/__about__.py +1 -1
  15. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/actions.py +0 -2
  16. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/cli.py +0 -3
  17. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/default_settings.yaml +1 -0
  18. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/lint.py +0 -1
  19. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/load.py +0 -5
  20. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/models/job.py +2 -0
  21. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/rule.py +0 -2
  22. bitwarden_workflow_linter-0.0.4/src/bitwarden_workflow_linter/rules/underscore_outputs.py +111 -0
  23. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/utils.py +0 -9
  24. bitwarden_workflow_linter-0.0.4/tests/fixtures/test-outputs-incorrect.yml +45 -0
  25. bitwarden_workflow_linter-0.0.4/tests/rules/test_underscore_output.py +259 -0
  26. bitwarden_workflow_linter-0.0.3/.github/workflows/_version_type.yml +0 -60
  27. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/.editorconfig +0 -0
  28. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/.gitattributes +0 -0
  29. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  30. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  31. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/.husky/pre-commit +0 -0
  32. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/.python-version +0 -0
  33. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/CONTRIBUTING.md +0 -0
  34. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/LICENSE.txt +0 -0
  35. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/Pipfile +0 -0
  36. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/Pipfile.lock +0 -0
  37. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/SECURITY.md +0 -0
  38. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/Taskfile.yml +0 -0
  39. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/pylintrc +0 -0
  40. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/pyproject.toml +0 -0
  41. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/pyproject.toml.tpl +0 -0
  42. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/__init__.py +0 -0
  43. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/default_actions.json +0 -0
  44. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/models/__init__.py +0 -0
  45. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/models/step.py +0 -0
  46. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/models/workflow.py +0 -0
  47. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/rules/__init__.py +0 -0
  48. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/rules/job_environment_prefix.py +0 -0
  49. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/rules/name_capitalized.py +0 -0
  50. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/rules/name_exists.py +0 -0
  51. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/rules/pinned_job_runner.py +0 -0
  52. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/rules/step_approved.py +0 -0
  53. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/src/bitwarden_workflow_linter/rules/step_pinned.py +0 -0
  54. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/__init__.py +0 -0
  55. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/conftest.py +0 -0
  56. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/fixtures/test-alt.yml +0 -0
  57. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/fixtures/test-min-incorrect.yaml +0 -0
  58. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/fixtures/test-min.yaml +0 -0
  59. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/fixtures/test.yml +0 -0
  60. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/fixtures/test_a.yaml +0 -0
  61. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/rules/__init__.py +0 -0
  62. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/rules/test_job_environment_prefix.py +0 -0
  63. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/rules/test_name_capitalized.py +0 -0
  64. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/rules/test_name_exists.py +0 -0
  65. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/rules/test_pinned_job_runner.py +0 -0
  66. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/rules/test_step_approved.py +0 -0
  67. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/rules/test_step_pinned.py +0 -0
  68. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/test_job.py +0 -0
  69. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/test_lint.py +0 -0
  70. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/test_load.py +0 -0
  71. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/test_rule.py +0 -0
  72. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/test_step.py +0 -0
  73. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/test_utils.py +0 -0
  74. {bitwarden_workflow_linter-0.0.3 → bitwarden_workflow_linter-0.0.4}/tests/test_workflow.py +0 -0
@@ -5,4 +5,4 @@
5
5
  # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
6
6
 
7
7
  # Default file owners
8
- * @bitwarden/dept-devops
8
+ * @bitwarden/dept-bre
@@ -2,6 +2,7 @@
2
2
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
3
  "extends": ["github>bitwarden/renovate-config"],
4
4
  "enabledManagers": ["github-actions", "npm", "pipenv"],
5
+ "labels": ["version:patch"],
5
6
  "packageRules": [
6
7
  {
7
8
  "groupName": "gh minor",
@@ -0,0 +1,57 @@
1
+ name: _version_type
2
+ run-name: Get version type
3
+
4
+ on:
5
+ workflow_call:
6
+ outputs:
7
+ version_bump_type:
8
+ description: "version to be built"
9
+ value: ${{ jobs.version.outputs.bump_type }}
10
+
11
+ jobs:
12
+ version:
13
+ name: Calculate Version
14
+ runs-on: ubuntu-22.04
15
+ outputs:
16
+ bump_type: ${{ steps.bump-type.outputs.type }}
17
+ steps:
18
+ - name: Get PR ID
19
+ id: pr
20
+ env:
21
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22
+ run: |
23
+ commit_message=$(
24
+ curl -s -L \
25
+ -H "Accept: application/vnd.github+json" \
26
+ -H "Authorization: Bearer $GH_TOKEN" \
27
+ -H "X-GitHub-Api-Version: 2022-11-28" \
28
+ https://api.github.com/repos/${{ github.repository }}/commits/${{ github.sha }} | \
29
+ jq -r ".commit.message"
30
+ )
31
+ ID=$(echo "$commit_message" | head -1 | grep -o "(#.*)" | grep -o "[0-9]*")
32
+ echo "id=$ID" >> $GITHUB_OUTPUT
33
+
34
+ - name: Get version bump type
35
+ id: bump-type
36
+ env:
37
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
38
+ PR_NUMBER: ${{ steps.pr.outputs.id }}
39
+ run: |
40
+ version_tag=$(
41
+ curl -s -L \
42
+ -H "Accept: application/vnd.github+json" \
43
+ -H "Authorization: Bearer $GH_TOKEN" \
44
+ -H "X-GitHub-Api-Version: 2022-11-28" \
45
+ https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUMBER/labels | \
46
+ jq -r ".[].name" | grep "version"
47
+ )
48
+
49
+ # Single Version label Enforcement (should go in CI...)
50
+ if [[ $(echo $version_tag | wc -w) -gt 1 ]]; then
51
+ echo "[!] multiple version labels found!"
52
+ exit 1
53
+ fi
54
+
55
+ version_type=$(echo $version_tag | cut -d ":" -f 2)
56
+ echo "Version Bump Type: $version_type"
57
+ echo "type=$version_type" >> $GITHUB_OUTPUT
@@ -1,40 +1,50 @@
1
- ---
2
1
  name: CD
3
- run-name: CD ${{ inputs.release_type }}
4
2
 
5
3
  on:
6
- push:
4
+ pull_request:
5
+ types:
6
+ - closed
7
7
  branches:
8
8
  - main
9
9
  paths:
10
10
  - "src/**"
11
- workflow_dispatch:
12
- inputs:
13
- release_type:
14
- description: 'Release type'
15
- required: true
16
- type: choice
17
- default: 'Dry Run'
18
- options:
19
- - 'Dry Run'
20
- - 'Release'
21
11
 
22
12
  jobs:
23
13
  version-type:
14
+ name: Get version type
15
+ if: github.event.pull_request.merged == true
24
16
  uses: ./.github/workflows/_version_type.yml
25
17
 
26
18
  version-bump:
27
19
  name: Version bump
20
+ if: github.event.pull_request.merged == true
28
21
  runs-on: ubuntu-22.04
29
22
  needs: version-type
30
23
  outputs:
31
24
  version: ${{ steps.get-version.outputs.version }}
32
25
  steps:
26
+ - name: Login to Azure - CI Subscription
27
+ uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
28
+ with:
29
+ creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
30
+
31
+ - name: Retrieve secrets
32
+ id: retrieve-secrets
33
+ uses: bitwarden/gh-actions/get-keyvault-secrets@main
34
+ with:
35
+ keyvault: "bitwarden-ci"
36
+ secrets: "github-gpg-private-key,
37
+ github-gpg-private-key-passphrase,
38
+ github-pat-bitwarden-devops-bot-repo-scope"
39
+
33
40
  - name: Check out repo
34
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
41
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
42
+ with:
43
+ fetch-depth: 0
44
+ token: ${{ steps.retrieve-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
35
45
 
36
46
  - name: Set up Python
37
- uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
47
+ uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
38
48
  with:
39
49
  python-version-file: ".python-version"
40
50
 
@@ -53,22 +63,8 @@ jobs:
53
63
  VERSION=$(hatch version)
54
64
  echo "version=$VERSION" >> $GITHUB_OUTPUT
55
65
 
56
- - name: Login to Azure - CI Subscription
57
- uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
58
- with:
59
- creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
60
-
61
- - name: Retrieve secrets
62
- id: retrieve-secrets
63
- uses: bitwarden/gh-actions/get-keyvault-secrets@main
64
- with:
65
- keyvault: "bitwarden-ci"
66
- secrets: "github-gpg-private-key,
67
- github-gpg-private-key-passphrase,
68
- github-pat-bitwarden-devops-bot-repo-scope"
69
-
70
66
  - name: Import GPG key
71
- uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0
67
+ uses: crazy-max/ghaction-import-gpg@cb9bde2e2525e640591a934b1fd28eef1dcaf5e5 # v6.2.0
72
68
  with:
73
69
  gpg_private_key: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key }}
74
70
  passphrase: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key-passphrase }}
@@ -84,41 +80,41 @@ jobs:
84
80
  env:
85
81
  OLD_VERSION: ${{ env.OLD_VERSION }}
86
82
  VERSION: ${{ steps.get-version.outputs.version }}
87
- if: ${{ github.event_name == 'push' }} || ${{ inputs.release_type != 'Dry Run' }}
88
83
  run: |
89
84
  git commit -am "Bump version from $OLD_VERSION to $VERSION"
90
- git tag $VERSION
85
+ git tag v$VERSION
91
86
  git push
92
87
  git push --tags
93
88
 
94
89
  release:
95
90
  name: GitHub release
91
+ if: github.event.pull_request.merged == true
96
92
  runs-on: ubuntu-22.04
97
93
  needs: version-bump
98
- if: ${{ github.event_name == 'push' }} || ${{ inputs.release_type != 'Dry Run' }}
99
94
  steps:
100
95
  - name: Check out repo
101
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
96
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
102
97
 
103
98
  - name: Create GitHub release
104
99
  uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5 # v1.14.0
105
100
  with:
106
101
  commit: ${{ github.sha }}
107
- tag: v${{ steps.version-bump.outputs.version }}
108
- name: Version version-bump
102
+ tag: v${{ steps.get-version.outputs.version }}
103
+ name: v${{ steps.get-version.outputs.version }}
109
104
  token: ${{ secrets.GITHUB_TOKEN }}
110
105
  draft: false
111
106
 
112
107
  deploy:
113
108
  name: Deploy workflow-linter (v2)
109
+ if: github.event.pull_request.merged == true
114
110
  runs-on: ubuntu-22.04
115
111
  needs: version-bump
116
112
  steps:
117
113
  - name: Check out repo
118
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
114
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
119
115
 
120
116
  - name: Set up Python
121
- uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
117
+ uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
122
118
  with:
123
119
  python-version-file: ".python-version"
124
120
 
@@ -135,22 +131,13 @@ jobs:
135
131
  uses: bitwarden/gh-actions/get-keyvault-secrets@main
136
132
  with:
137
133
  keyvault: "bitwarden-ci"
138
- secrets: "pypi-api-token,
139
- pypi-test-api-token"
134
+ secrets: "pypi-api-token"
140
135
 
141
136
  - name: Build
142
137
  run: hatch build
143
138
 
144
139
  - name: Publish
145
- if: ${{ github.event_name == 'push' }} || ${{ inputs.release_type != 'Dry Run' }}
146
140
  env:
147
141
  HATCH_INDEX_USER: __token__
148
142
  HATCH_INDEX_AUTH: ${{ steps.retrieve-secret.outputs.pypi-api-token }}
149
143
  run: hatch publish
150
-
151
- - name: Dry Run - Publish
152
- if: ${{ github.event_name == 'workflow_dispatch' }} && ${{ inputs.release_type == 'Dry Run' }}
153
- env:
154
- HATCH_INDEX_USER: __token__
155
- HATCH_INDEX_AUTH: ${{ steps.retrieve-secret.outputs.pypi-test-api-token }}
156
- run: hatch publish -r test
@@ -13,10 +13,10 @@ jobs:
13
13
  runs-on: ubuntu-22.04
14
14
  steps:
15
15
  - name: Check out repo
16
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
16
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
17
17
 
18
18
  - name: Set up Python
19
- uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
19
+ uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
20
20
  with:
21
21
  python-version-file: ".python-version"
22
22
 
@@ -1,4 +1,3 @@
1
- ---
2
1
  name: Enforce PR labels
3
2
 
4
3
  on:
@@ -9,7 +8,7 @@ jobs:
9
8
  uses: bitwarden/gh-actions/.github/workflows/_enforce-labels.yml@main
10
9
 
11
10
  enforce-version-label:
12
- if: ${{ !contains(github.event.*.labels.*.name, 'version') }}
11
+ if: "!(contains(github.event.pull_request.labels.*.name, 'version:major') || contains(github.event.pull_request.labels.*.name, 'version:minor') || contains(github.event.pull_request.labels.*.name, 'version:patch'))"
13
12
  name: Enforce version label
14
13
  runs-on: ubuntu-22.04
15
14
 
@@ -26,12 +26,12 @@ jobs:
26
26
 
27
27
  steps:
28
28
  - name: Check out repo
29
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
29
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
30
30
  with:
31
31
  ref: ${{ github.event.pull_request.head.sha }}
32
32
 
33
33
  - name: Scan with Checkmarx
34
- uses: checkmarx/ast-github-action@831a8d51a8a0535c0399f9c12728d8d3cc22d850 # 2.0.28
34
+ uses: checkmarx/ast-github-action@f0869bd1a37fddc06499a096101e6c900e815d81 # 2.0.36
35
35
  env:
36
36
  INCREMENTAL: "${{ contains(github.event_name, 'pull_request') && '--sast-incremental' || '' }}"
37
37
  with:
@@ -46,7 +46,7 @@ jobs:
46
46
  --output-path . ${{ env.INCREMENTAL }}
47
47
 
48
48
  - name: Upload Checkmarx results to GitHub
49
- uses: github/codeql-action/upload-sarif@9fdb3e49720b44c48891d036bb502feb25684276 # v3.25.6
49
+ uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0
50
50
  with:
51
51
  sarif_file: cx_result.sarif
52
52
 
@@ -60,13 +60,13 @@ jobs:
60
60
 
61
61
  steps:
62
62
  - name: Check out repo
63
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
63
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
64
64
  with:
65
65
  fetch-depth: 0
66
66
  ref: ${{ github.event.pull_request.head.sha }}
67
67
 
68
68
  - name: Scan with SonarCloud
69
- uses: sonarsource/sonarcloud-github-action@4006f663ecaf1f8093e8e4abb9227f6041f52216 # v2.2.0
69
+ uses: sonarsource/sonarcloud-github-action@383f7e52eae3ab0510c3cb0e7d9d150bbaeab838 # v3.1.0
70
70
  env:
71
71
  SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
72
72
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -30,3 +30,8 @@ dist
30
30
  ## Dev Environments
31
31
  Session.vim
32
32
  flake.*
33
+
34
+
35
+ # Python
36
+ **/__pycache__/**
37
+ *.pyc
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bitwarden_workflow_linter
3
- Version: 0.0.3
3
+ Version: 0.0.4
4
4
  Summary: Custom GitHub Action Workflow Linter
5
5
  Project-URL: Homepage, https://github.com/bitwarden/workflow-linter
6
6
  Project-URL: Issues, https://github.com/bitwarden/workflow-linter/issues
@@ -66,6 +66,7 @@ enabled_rules:
66
66
  - bitwarden_workflow_linter.rules.pinned_job_runner.RuleJobRunnerVersionPinned
67
67
  - bitwarden_workflow_linter.rules.job_environment_prefix.RuleJobEnvironmentPrefix
68
68
  - bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
69
+ - bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs
69
70
 
70
71
  approved_actions_path: default_actions.json
71
72
  ```
@@ -177,6 +178,9 @@ By default, a new Rule needs five things:
177
178
  not support Rules that check against multiple objects at a time OR file level formatting (one empty between each step or
178
179
  two empty lines between each job)
179
180
 
181
+ To activate a rule after implementing it, add it to `settings.yaml` in the project's base folder
182
+ and `src/bitwarden_workflow_linter/default_settings.yaml` to make the rule default
183
+
180
184
  ### ToDo
181
185
 
182
186
  - [ ] Add Rule to assert correct format for single line run
@@ -40,6 +40,7 @@ enabled_rules:
40
40
  - bitwarden_workflow_linter.rules.pinned_job_runner.RuleJobRunnerVersionPinned
41
41
  - bitwarden_workflow_linter.rules.job_environment_prefix.RuleJobEnvironmentPrefix
42
42
  - bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
43
+ - bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs
43
44
 
44
45
  approved_actions_path: default_actions.json
45
46
  ```
@@ -151,6 +152,9 @@ By default, a new Rule needs five things:
151
152
  not support Rules that check against multiple objects at a time OR file level formatting (one empty between each step or
152
153
  two empty lines between each job)
153
154
 
155
+ To activate a rule after implementing it, add it to `settings.yaml` in the project's base folder
156
+ and `src/bitwarden_workflow_linter/default_settings.yaml` to make the rule default
157
+
154
158
  ### ToDo
155
159
 
156
160
  - [ ] Add Rule to assert correct format for single line run
@@ -10,8 +10,8 @@
10
10
  "license": "SEE LICENSE IN LICENSE.txt",
11
11
  "devDependencies": {
12
12
  "husky": "9.0.11",
13
- "lint-staged": "15.2.5",
14
- "prettier": "3.2.5"
13
+ "lint-staged": "15.2.7",
14
+ "prettier": "3.3.2"
15
15
  }
16
16
  },
17
17
  "node_modules/ansi-escapes": {
@@ -322,9 +322,9 @@
322
322
  }
323
323
  },
324
324
  "node_modules/lint-staged": {
325
- "version": "15.2.5",
326
- "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.5.tgz",
327
- "integrity": "sha512-j+DfX7W9YUvdzEZl3Rk47FhDF6xwDBV5wwsCPw6BwWZVPYJemusQmvb9bRsW23Sqsaa+vRloAWogbK4BUuU2zA==",
325
+ "version": "15.2.7",
326
+ "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.7.tgz",
327
+ "integrity": "sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw==",
328
328
  "dev": true,
329
329
  "license": "MIT",
330
330
  "dependencies": {
@@ -543,9 +543,9 @@
543
543
  }
544
544
  },
545
545
  "node_modules/prettier": {
546
- "version": "3.2.5",
547
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
548
- "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
546
+ "version": "3.3.2",
547
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
548
+ "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==",
549
549
  "dev": true,
550
550
  "license": "MIT",
551
551
  "bin": {
@@ -14,8 +14,8 @@
14
14
  "homepage": "https://bitwarden.com",
15
15
  "devDependencies": {
16
16
  "husky": "9.0.11",
17
- "lint-staged": "15.2.5",
18
- "prettier": "3.2.5"
17
+ "lint-staged": "15.2.7",
18
+ "prettier": "3.3.2"
19
19
  },
20
20
  "lint-staged": {
21
21
  "!(*.py)": "prettier --cache --write --ignore-unknown",
@@ -4,5 +4,6 @@ enabled_rules:
4
4
  - bitwarden_workflow_linter.rules.pinned_job_runner.RuleJobRunnerVersionPinned
5
5
  - bitwarden_workflow_linter.rules.job_environment_prefix.RuleJobEnvironmentPrefix
6
6
  - bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
7
+ - bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs
7
8
 
8
9
  approved_actions_path: default_actions.json
@@ -1,3 +1,3 @@
1
1
  """Metadata for Workflow Linter."""
2
2
 
3
- __version__ = "0.0.3"
3
+ __version__ = "0.0.4"
@@ -11,13 +11,11 @@ from typing import Optional, Union
11
11
 
12
12
  from .utils import Colors, Settings, Action
13
13
 
14
-
15
14
  class GitHubApiSchemaError(Exception):
16
15
  """A generic Exception to catch redefinitions of GitHub Api Schema changes."""
17
16
 
18
17
  pass
19
18
 
20
-
21
19
  class ActionsCmd:
22
20
  """Command to manage the pre-approved list of Actions
23
21
 
@@ -9,10 +9,8 @@ from .actions import ActionsCmd
9
9
  from .lint import LinterCmd
10
10
  from .utils import Settings
11
11
 
12
-
13
12
  local_settings = Settings.factory()
14
13
 
15
-
16
14
  def main(input_args: Optional[List[str]] = None) -> int:
17
15
  """CLI utility to lint GitHub Action Workflows.
18
16
 
@@ -50,6 +48,5 @@ def main(input_args: Optional[List[str]] = None) -> int:
50
48
 
51
49
  return -1
52
50
 
53
-
54
51
  if __name__ == "__main__":
55
52
  sys.exit(main())
@@ -4,5 +4,6 @@ enabled_rules:
4
4
  - bitwarden_workflow_linter.rules.pinned_job_runner.RuleJobRunnerVersionPinned
5
5
  - bitwarden_workflow_linter.rules.job_environment_prefix.RuleJobEnvironmentPrefix
6
6
  - bitwarden_workflow_linter.rules.step_pinned.RuleStepUsesPinned
7
+ - bitwarden_workflow_linter.rules.underscore_outputs.RuleUnderscoreOutputs
7
8
 
8
9
  approved_actions_path: default_actions.json
@@ -10,7 +10,6 @@ from typing import Optional
10
10
  from .load import WorkflowBuilder, Rules
11
11
  from .utils import LintFinding, Settings
12
12
 
13
-
14
13
  class LinterCmd:
15
14
  """Command to lint GitHub Action Workflow files
16
15
 
@@ -13,16 +13,13 @@ from .models.workflow import Workflow
13
13
  from .rule import Rule
14
14
  from .utils import Settings
15
15
 
16
-
17
16
  yaml = YAML()
18
17
 
19
-
20
18
  class WorkflowBuilderError(Exception):
21
19
  """Exception to indicate an error with the WorkflowBuilder."""
22
20
 
23
21
  pass
24
22
 
25
-
26
23
  class WorkflowBuilder:
27
24
  """Collection of methods to build Workflow objects."""
28
25
 
@@ -85,13 +82,11 @@ class WorkflowBuilder:
85
82
  "The workflow must either be built from a file or from a CommentedMap"
86
83
  )
87
84
 
88
-
89
85
  class LoadRulesError(Exception):
90
86
  """Exception to indicate an error with loading rules."""
91
87
 
92
88
  pass
93
89
 
94
-
95
90
  class Rules:
96
91
  """A collection of all of the types of rules.
97
92
 
@@ -30,6 +30,7 @@ class Job:
30
30
  uses_with: Optional[CommentedMap] = field(
31
31
  metadata=config(field_name="with"), default=None
32
32
  )
33
+ outputs: Optional[CommentedMap] = None
33
34
 
34
35
  @classmethod
35
36
  def init(cls: Self, key: str, data: CommentedMap) -> Self:
@@ -39,6 +40,7 @@ class Job:
39
40
  "name": data["name"] if "name" in data else None,
40
41
  "runs-on": data["runs-on"] if "runs-on" in data else None,
41
42
  "env": data["env"] if "env" in data else None,
43
+ "outputs": data["outputs"] if "outputs" in data else None,
42
44
  }
43
45
 
44
46
  new_job = cls.from_dict(init_data)
@@ -7,13 +7,11 @@ from .models.job import Job
7
7
  from .models.step import Step
8
8
  from .utils import LintFinding, LintLevels, Settings
9
9
 
10
-
11
10
  class RuleExecutionException(Exception):
12
11
  """Exception for the Base Rule class."""
13
12
 
14
13
  pass
15
14
 
16
-
17
15
  class Rule:
18
16
  """Base class of a Rule to extend to create a linting Rule."""
19
17
 
@@ -0,0 +1,111 @@
1
+ import re
2
+
3
+ from typing import Optional, Union, Tuple
4
+
5
+ from ..models.job import Job
6
+ from ..rule import Rule
7
+ from ..models.workflow import Workflow
8
+ from ..models.step import Step
9
+ from ..utils import LintLevels, Settings
10
+
11
+
12
+ class RuleUnderscoreOutputs(Rule):
13
+ """Rule to enforce all GitHub 'outputs' more than one words contain an underscore.
14
+
15
+ A simple standard to ensure uniformity in naming.
16
+ """
17
+
18
+ def __init__(self, settings: Optional[Settings] = None) -> None:
19
+ """Constructor for RuleUnderscoreOutputs to override the Rule class.
20
+
21
+ Args:
22
+ settings:
23
+ A Settings object that contains any default, overridden, or custom settings
24
+ required anywhere in the application.
25
+ """
26
+ self.message = "outputs with more than one word must use an underscore"
27
+ self.on_fail = LintLevels.WARNING
28
+ self.compatibility = [Workflow, Job, Step]
29
+ self.settings = settings
30
+
31
+ def fn(self, obj: Union[Workflow, Job, Step]) -> Tuple[bool, str]:
32
+ """Enforces all outputs to have an underscore in the key name.
33
+
34
+ This Rule checks all outputs in a Workflow, Job, or Step to ensure that
35
+ the key name contains an underscore. This is to ensure that the naming
36
+ convention is consistent across all outputs in the workflow configuration
37
+
38
+ Example:
39
+ ---
40
+ on:
41
+ workflow_dispatch:
42
+ outputs:
43
+ registry:
44
+ value: 'Test Value'
45
+ some_registry:
46
+ value: 'Test Value'
47
+ workflow_call:
48
+ outputs:
49
+ registry:
50
+ value: 'Test Value'
51
+ some_registry:
52
+ value: 'Test Value'
53
+ jobs:
54
+ job-key:
55
+ runs-on: ubuntu-22.04
56
+ outputs:
57
+ test_key_job: ${{ steps.test_output_1.outputs.test_key }}
58
+ steps:
59
+ - name: Test output in one-line run step
60
+ id: test_output_1
61
+ run: echo "test_key_1=Test-Value1" >> $GITHUB_OUTPUT
62
+
63
+ - name: Test output in multi-line run step
64
+ id: test_output_2
65
+ run: |
66
+ echo
67
+ fake-command=Test-Value2
68
+ echo "test_key_2=$REF" >> $GITHUB_OUTPUT
69
+ echo "deployed_ref=$DEPLOYED_REF" >> $GITHUB_OUTPUT
70
+
71
+ - name: Test step with no run
72
+ id: test_output_3
73
+ uses: actions/checkout@v2
74
+ with:
75
+ ref: ${{ github.ref }}
76
+ fetch-depth: 0
77
+
78
+ In this example, in workflow level 'registry' and 'some_registry' are outputs
79
+ that satisfy the rule in both 'workflow_dispatch' and 'workflow_call' events.
80
+ In job level 'test_key_job' satisfies the rule.
81
+ In step level 'test_key_1', 'test_key_2', and 'deployed_ref' satisfy the rule.
82
+
83
+ See tests/rules/test_underscore_outputs.py for incorrect examples.
84
+ """
85
+
86
+ outputs = []
87
+
88
+ if isinstance(obj, Workflow):
89
+ if obj.on.get("workflow_dispatch"):
90
+ outputs.extend(obj.on["workflow_dispatch"]["outputs"].keys())
91
+
92
+ if obj.on.get("workflow_call"):
93
+ outputs.extend(obj.on["workflow_call"]["outputs"].keys())
94
+
95
+ if isinstance(obj, Job):
96
+ if obj.outputs:
97
+ outputs.extend(obj.outputs.keys())
98
+
99
+ if isinstance(obj, Step):
100
+ if obj.run:
101
+ outputs.extend(re.findall(
102
+ r"\b([a-zA-Z0-9_-]+)\s*=\s*[^=]*>>\s*\$GITHUB_OUTPUT",
103
+ obj.run))
104
+
105
+ for output_name in outputs:
106
+ if "-" in output_name:
107
+ return False, (
108
+ f"Hyphen found in {obj.__class__.__name__} output: {output_name}"
109
+ )
110
+
111
+ return True, ""
@@ -10,10 +10,8 @@ from typing import Optional, Self, TypeVar
10
10
 
11
11
  from ruamel.yaml import YAML
12
12
 
13
-
14
13
  yaml = YAML()
15
14
 
16
-
17
15
  @dataclass
18
16
  class Colors:
19
17
  """Class containing color codes for printing strings to output."""
@@ -27,7 +25,6 @@ class Colors:
27
25
  cyan = "36m"
28
26
  white = "37m"
29
27
 
30
-
31
28
  @dataclass
32
29
  class LintLevel:
33
30
  """Class to contain the numeric level and color of linting."""
@@ -35,7 +32,6 @@ class LintLevel:
35
32
  code: int
36
33
  color: Colors
37
34
 
38
-
39
35
  class LintLevels(LintLevel, Enum):
40
36
  """Collection of the different types of LintLevels available."""
41
37
 
@@ -43,7 +39,6 @@ class LintLevels(LintLevel, Enum):
43
39
  WARNING = 1, Colors.yellow
44
40
  ERROR = 2, Colors.red
45
41
 
46
-
47
42
  class LintFinding:
48
43
  """Represents a problem detected by linting."""
49
44
 
@@ -62,7 +57,6 @@ class LintFinding:
62
57
  f"{self.description}"
63
58
  )
64
59
 
65
-
66
60
  @dataclass
67
61
  class Action:
68
62
  """Collection of the metadata associated with a GitHub Action."""
@@ -99,16 +93,13 @@ class Action:
99
93
  """
100
94
  return not self.__eq__(other)
101
95
 
102
-
103
96
  class SettingsError(Exception):
104
97
  """Custom Exception to indicate an error with loading Settings."""
105
98
 
106
99
  pass
107
100
 
108
-
109
101
  SettingsFromFactory = TypeVar("SettingsFromFactory", bound="Settings")
110
102
 
111
-
112
103
  class Settings:
113
104
  """Class that contains configuration-as-code for any portion of the app."""
114
105
 
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: Test Incorrect Workflow
3
+ on:
4
+ workflow_dispatch:
5
+ outputs:
6
+ registry-1:
7
+ value: 'Test Value'
8
+ some_registry-1:
9
+ value: 'Test Value'
10
+ workflow-call:
11
+ outputs:
12
+ registry-2:
13
+ value: 'Test Value'
14
+ push: {}
15
+
16
+ jobs:
17
+ job-key:
18
+ name: Test Incorrect Job
19
+ runs-on: ubuntu-22.04
20
+ outputs:
21
+ test-key-1: ${{ steps.test_output_1.outputs.test_key }}
22
+ steps:
23
+ - name: Test output in one-line run step
24
+ id: test_output_1
25
+ run: echo "test-key-1=Test-Value1" >> $GITHUB_OUTPUT
26
+
27
+ - name: Test output in multi-line run step
28
+ id: test_output_2
29
+ run: |
30
+ echo
31
+ fake-command
32
+ echo "test-key-2=$REF" >> $GITHUB_OUTPUT
33
+ echo "deployed-ref=$DEPLOYED_REF" >> $GITHUB_OUTPUT
34
+
35
+ - name: Test step with one-line run and no Output
36
+ id: test_output_3
37
+ run: echo "test-key-3"
38
+
39
+ - name: Test step with multi-line run and no Output
40
+ id: test_output_4
41
+ run: |
42
+ echo
43
+ fake-command=Test-Value4
44
+ echo "test-key-4"
45
+ echo "deployed-ref"
@@ -0,0 +1,259 @@
1
+ """Test src/bitwarden_workflow_linter/rules/underscore_outputs.py."""
2
+
3
+ import pytest
4
+
5
+ from ruamel.yaml import YAML
6
+
7
+ from src.bitwarden_workflow_linter.load import WorkflowBuilder
8
+ from src.bitwarden_workflow_linter.rules.underscore_outputs import RuleUnderscoreOutputs
9
+
10
+ yaml = YAML()
11
+
12
+
13
+ @pytest.fixture(name="correct_workflow")
14
+ def fixture_correct_workflow():
15
+ workflow = """\
16
+ ---
17
+ name: Test Correct Workflow
18
+ on:
19
+ workflow_dispatch:
20
+ outputs:
21
+ registry:
22
+ value: 'Test Value'
23
+ some_registry:
24
+ value: 'Test Value'
25
+ workflow_call:
26
+ outputs:
27
+ registry:
28
+ value: 'Test Value'
29
+ some_registry:
30
+ value: 'Test Value'
31
+ push: {}
32
+
33
+ jobs:
34
+ job-key:
35
+ name: Test Correct Job
36
+ runs-on: ubuntu-22.04
37
+ outputs:
38
+ test_key_job: ${{ steps.test_output_1.outputs.test_key }}
39
+ steps:
40
+ - name: Test output in one-line run step
41
+ id: test_output_1
42
+ run: echo "test_key_1=Test-Value1" >> $GITHUB_OUTPUT
43
+
44
+ - name: Test output in multi-line run step
45
+ id: test_output_2
46
+ run: |
47
+ echo
48
+ fake-command=Test-Value2
49
+ echo "test_key_2=$REF" >> $GITHUB_OUTPUT
50
+ echo "deployed_ref=$DEPLOYED_REF" >> $GITHUB_OUTPUT
51
+
52
+ - name: Test step with one-line run and no Output
53
+ id: test_output_3
54
+ run: echo "test_key_3"
55
+
56
+ - name: Test step with multi-line run and no Output
57
+ id: test_output_4
58
+ run: |
59
+ echo
60
+ fake-command=Test-Value4
61
+ echo "test_key_4"
62
+ echo "deployed_ref"
63
+
64
+ - name: Test step with no run
65
+ id: test_output_5
66
+ uses: actions/checkout@v2
67
+ with:
68
+ ref: ${{ github.ref }}
69
+ fetch-depth: 0
70
+ """
71
+ return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
72
+
73
+
74
+ @pytest.fixture(name="incorrect_workflow")
75
+ def fixture_incorrect_workflow():
76
+ workflow = """\
77
+ ---
78
+ name: Test Incorrect Workflow
79
+ on:
80
+ workflow_dispatch:
81
+ outputs:
82
+ registry-1:
83
+ value: 'Test Value'
84
+ some_registry-1:
85
+ value: 'Test Value'
86
+ workflow_call:
87
+ outputs:
88
+ registry-2:
89
+ value: 'Test Value'
90
+ push: {}
91
+
92
+ jobs:
93
+ job-key:
94
+ name: Test Incorrect Job
95
+ runs-on: ubuntu-22.04
96
+ outputs:
97
+ test-key-1: ${{ steps.test_output_1.outputs.test_key }}
98
+ steps:
99
+ - name: Test output in one-line run step
100
+ id: test_output_1
101
+ run: echo "test-key-1=Test-Value1" >> $GITHUB_OUTPUT
102
+
103
+ - name: Test output in multi-line run step
104
+ id: test_output_2
105
+ run: |
106
+ echo
107
+ fake-command
108
+ echo "test-key-2=$REF" >> $GITHUB_OUTPUT
109
+ echo "deployed-ref=$DEPLOYED_REF" >> $GITHUB_OUTPUT
110
+
111
+ - name: Test step with one-line run and no Output
112
+ id: test_output_3
113
+ run: echo "test-key-3"
114
+
115
+ - name: Test step with multi-line run and no Output
116
+ id: test_output_4
117
+ run: |
118
+ echo
119
+ fake-command=Test-Value4
120
+ echo "test-key-4"
121
+ echo "deployed-ref"
122
+ """
123
+ return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
124
+
125
+
126
+ @pytest.fixture(name="push_only_workflow")
127
+ def fixture_push_only_workflow():
128
+ workflow = """\
129
+ ---
130
+ name: Push Only
131
+ on:
132
+ push: {}
133
+
134
+ jobs:
135
+ job-key:
136
+ name: Test
137
+ runs-on: ubuntu-latest
138
+ steps:
139
+ - run: echo test
140
+
141
+ """
142
+ return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
143
+
144
+ @pytest.fixture(name="misc_workflow")
145
+ def fixture_misc_workflow():
146
+ workflow = """\
147
+ ---
148
+ name: Misc Workflow
149
+ on:
150
+ push: {}
151
+
152
+ jobs:
153
+ job-key:
154
+ runs-on: ubuntu-22.04
155
+ steps:
156
+ - name: Test Step
157
+ run: |
158
+ echo "test_value=$does_it_break" >> /tmp/test
159
+
160
+ - name: Test Step 2
161
+ run: |
162
+ TEST_FILE=/tmp/test2
163
+ echo "test_value=$does_it_break" >> $TEST_FILE
164
+ """
165
+ return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
166
+
167
+ @pytest.fixture(name="no_output_workflow")
168
+ def fixture_no_output_workflow():
169
+ workflow = """\
170
+ ---
171
+ name: No Output Workflow
172
+ on:
173
+ workflow_dispatch: {}
174
+ workflow_call: {}
175
+
176
+ jobs:
177
+ job-key:
178
+ name: Test
179
+ runs-on: ubuntu-latest
180
+ steps:
181
+ - run: echo test
182
+ """
183
+ return WorkflowBuilder.build(workflow=yaml.load(workflow), from_file=False)
184
+
185
+
186
+
187
+ @pytest.fixture(name="rule")
188
+ def fixture_rule():
189
+ return RuleUnderscoreOutputs()
190
+
191
+
192
+ def test_rule_on_correct_workflow(rule, correct_workflow):
193
+ result, _ = rule.fn(correct_workflow)
194
+ assert result is True
195
+
196
+
197
+ def test_rule_on_incorrect_workflow(rule, incorrect_workflow):
198
+ result, _ = rule.fn(incorrect_workflow)
199
+ assert result is False
200
+
201
+
202
+ def test_rule_on_correct_job(rule, correct_workflow):
203
+ result, _ = rule.fn(correct_workflow.jobs["job-key"])
204
+ assert result is True
205
+
206
+
207
+ def test_rule_on_incorrect_job(rule, incorrect_workflow):
208
+ result, _ = rule.fn(incorrect_workflow.jobs["job-key"])
209
+ assert result is False
210
+
211
+
212
+ def test_rule_on_correct_step(rule, correct_workflow):
213
+ result, _ = rule.fn(correct_workflow.jobs["job-key"].steps[0])
214
+ assert result is True
215
+
216
+ result, _ = rule.fn(correct_workflow.jobs["job-key"].steps[1])
217
+ assert result is True
218
+
219
+ result, _ = rule.fn(correct_workflow.jobs["job-key"].steps[2])
220
+ assert result is True
221
+
222
+ result, _ = rule.fn(correct_workflow.jobs["job-key"].steps[3])
223
+ assert result is True
224
+
225
+ result, _ = rule.fn(correct_workflow.jobs["job-key"].steps[4])
226
+ assert result is True
227
+
228
+
229
+ def test_rule_on_incorrect_step(rule, incorrect_workflow):
230
+ result, _ = rule.fn(incorrect_workflow.jobs["job-key"].steps[0])
231
+ assert result is False
232
+
233
+ result, message = rule.fn(incorrect_workflow.jobs["job-key"].steps[1])
234
+ assert result is False
235
+ assert message == "Hyphen found in Step output: test-key-2"
236
+
237
+ result, _ = rule.fn(incorrect_workflow.jobs["job-key"].steps[2])
238
+ assert result is True
239
+
240
+ result, _ = rule.fn(incorrect_workflow.jobs["job-key"].steps[3])
241
+ assert result is True
242
+
243
+
244
+ def test_rule_on_push_only_workflow(rule, push_only_workflow):
245
+ result, _ = rule.fn(push_only_workflow)
246
+ assert result is True
247
+
248
+
249
+ def test_rule_on_misc_workflow(rule, misc_workflow):
250
+ result, _ = rule.fn(misc_workflow.jobs["job-key"].steps[0])
251
+ assert result is True
252
+
253
+ result, _ = rule.fn(misc_workflow.jobs["job-key"].steps[1])
254
+ assert result is True
255
+
256
+
257
+ def test_rule_on_no_output_workflow(rule, no_output_workflow):
258
+ result, _ = rule.fn(no_output_workflow)
259
+ assert result is True
@@ -1,60 +0,0 @@
1
- ---
2
- name: _version_type
3
- run-name: Get version type
4
-
5
- on:
6
- workflow_call:
7
- outputs:
8
- version_bump_type:
9
- description: "version to be built"
10
- value: ${{ jobs.version.outputs.bump_type }}
11
-
12
- jobs:
13
- version:
14
- name: Calculate Version
15
- runs-on: ubuntu-22.04
16
- outputs:
17
- bump_type: ${{ steps.bump-type.outputs.type }}
18
- steps:
19
- # - name: Get PR ID
20
- # id: pr
21
- # env:
22
- # GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
23
- # run: |
24
- # commit_message=$(
25
- # curl -s -L \
26
- # -H "Accept: application/vnd.github+json" \
27
- # -H "Authorization: Bearer $GH_TOKEN" \
28
- # -H "X-GitHub-Api-Version: 2022-11-28" \
29
- # https://api.github.com/repos/${{ github.repository }}/commits/${{ github.sha }} | \
30
- # jq -r ".commit.message"
31
- # )
32
- # ID=$(echo "$commit_message" | head -1 | grep -o "(#.*)" | grep -o "[0-9]*")
33
- # echo "id=$ID" >> $GITHUB_OUTPUT
34
-
35
- - name: Get version bump type
36
- id: bump-type
37
- env:
38
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39
- PR_NUMBER: ${{ steps.pr.outputs.id }}
40
- run: |
41
- # version_tag=$(
42
- # curl -s -L \
43
- # -H "Accept: application/vnd.github+json" \
44
- # -H "Authorization: Bearer $GH_TOKEN" \
45
- # -H "X-GitHub-Api-Version: 2022-11-28" \
46
- # https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUMBER/labels | \
47
- # jq -r ".[].name" | grep "version"
48
- # )
49
-
50
- version_tag="version:patch"
51
-
52
- # Single Version label Enforcement (should go in CI...)
53
- if [[ $(echo $version_tag | wc -w) -gt 1 ]]; then
54
- echo "[!] multiple version labels found!"
55
- exit 1
56
- fi
57
-
58
- version_type=$(echo $version_tag | cut -d ":" -f 2)
59
- echo "Version Bump Type: $version_type"
60
- echo "type=$version_type" >> $GITHUB_OUTPUT