Skip to content

Commit

Permalink
Move lint-workflow to vs directory restore lint-workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
joseph-flinn committed Jan 12, 2024
1 parent e49cde4 commit 4ca8b81
Show file tree
Hide file tree
Showing 63 changed files with 1,822 additions and 805 deletions.
26 changes: 25 additions & 1 deletion .github/workflows/lint-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
workflow_dispatch: {}

jobs:
CI:
ci-lint:
name: CI
runs-on: ubuntu-22.04
steps:
Expand All @@ -30,4 +30,28 @@ jobs:
- name: Test lint
working-directory: lint-workflow
run: pipenv run pytest tests


ci-lint-v2:
name: CI
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

- name: Set up Python
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
with:
python-version: "3.11"

- name: Install dependencies
working-directory: lint-workflow-v2
run: |
python -m pip install --upgrade pip
pip install pipenv
pipenv install --dev
- name: Test lint
working-directory: lint-workflow-v2
run: pipenv run pytest tests --cov=src
File renamed without changes.
36 changes: 36 additions & 0 deletions lint-workflow-v2/.yamllint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---

extends: default

rules:
braces:
level: warning
brackets:
level: warning
colons:
level: warning
commas:
level: warning
comments:
min-spaces-from-content: 1
empty-lines:
level: warning
hyphens:
level: warning
indentation:
level: warning
spaces: 2
key-duplicates:
level: warning
line-length:
level: warning
max: 120
new-line-at-end-of-file:
level: warning
new-lines:
level: warning
trailing-spaces:
level: warning
truthy:
check-keys: false
level: warning
22 changes: 22 additions & 0 deletions lint-workflow-v2/Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
pyyaml = "*"
urllib3 = "*"
pydantic = "*"
"ruamel.yaml" = "*"
dataclasses-json = "*"

[dev-packages]
black = "*"
pytest = "*"
coverage = "*"
pytest-cov = "*"
pylint = "*"
pytype = "*"

[requires]
python_version = "3.11"
814 changes: 814 additions & 0 deletions lint-workflow-v2/Pipfile.lock

Large diffs are not rendered by default.

123 changes: 123 additions & 0 deletions lint-workflow-v2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# lint-workflow

## Usage

There is currently NO packaging or distribution of this CLI tool. Until such time, the `cli.py` file needs to be run
with python 3.11+.

`python cli.py --help`


```
usage: workflow-linter [-h] [-v] {lint,actions} ...
positional arguments:
{lint,actions}
lint Verify that a GitHub Action Workflow follows all of the Rules.
actions Add or Update Actions in the pre-approved list.
options:
-h, --help show this help message and exit
-v, --verbose
```

## Development
### Requirements

- Python 3.11
- pipenv

### Setup

```
pipenv install --dev
pipenv shell
```

### Testing

All built-in `src/rules` should have 100% code coverage and we should shoot for an overall coverage of 80%+.
We are lax on the
[imperative shell](https://www.destroyallsoftware.com/screencasts/catalog/functional-core-imperative-shell)
(code interacting with other systems; ie. disk, network, etc), but we strive to maintain a high coverage over the
funcationl core (objects and models).

```
pipenv shell
pytest tests --cov=src
```

### Code Reformatting

We adhere to PEP8 and use `black` to maintain this adherence. `black` should be run on any change being merged
to `main`.

```
pipenv shell
black .
```

### Linting

We loosely use [Google's Python style guide](https://google.github.io/styleguide/pyguide.html), but yield to
`black` when there is a conflict

```
pipenv shell
pylint --rcfile pylintrc src/ tests/
```

### Add a new Rule

A new Rule is created by extending the Rule base class and overriding the `fn(obj: Union[Workflow, Job, Step])` method.
Available attributes of `Workflows`, `Jobs` and `Steps` can be found in their definitons under `src/models`.

For a simple example, we'll take a look at enforcing the existence of the `name` key in a Job. This is already done by
default with the src.rules.name_exists.RuleNameExists, but provides a simple enough example to walk through.

```python
from typing import Union, Tuple

from ..rule import Rule
from ..models.job import Job
from ..models.workflow import Workflow
from ..models.step import Step
from ..utils import LintLevels, Settings


class RuleJobNameExists(Rule):
def __init__(self, settings: Settings = None) -> None:
self.message = "name must exist"
self.on_fail: LintLevels = LintLevels.ERROR
self.compatibility: List[Union[Workflow, Job, Step]] = [Job]
self.settings: Settings = settings

def fn(self, obj: Job) -> Tuple[bool, str]:
"""<doc block goes here> """
if obj.name is not None:
return True, ""
return False, self.message
```

[TODO: Is this enough documentation on how to use?]

By default, a new Rule needs five things:

- `self.message`: The message to return to the user on a lint failure
- `self.on_fail`: The level of failure on a lint failure (NONE, WARNING, ERROR).
NONE and WARNING will exit with a code of 0 (unless using `strict` mode for WARNING).
ERROR will exit with a non-zero exit code
- `self.compatibility`: The list of objects this rule is compatible with. This is used to create separate instances of
the Rule for each object in the Rules collection.
- `self.settings`: In general, this should default to what is shown here, but allows for overrides
- `self.fn`: The function doing the actual work to check the object and enforce the standardenforcing.

`fn` can be as simple or as complex as it needs to be to run a check on a _single_ object. This linter currently does
not support Rules that check against multiple objects at a time OR file level formatting (one empty between each step or
two empty lines between each job)


### ToDo

- [ ] Add Rule to assert correct format for single line run

File renamed without changes.
32 changes: 32 additions & 0 deletions lint-workflow-v2/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: 'Lint Workflow'
description: 'Lints GitHub Actions Workflow'
inputs:
workflows:
description: "Path to workflow file(s)"
required: true
runs:
using: "composite"
steps:
- name: Install dependencies
run: pip install --user yamllint
shell: bash

- name: Setup
id: setup
run: |
FORMAT_PATH=$(echo ${{ inputs.workflows }} | sed 's/ *$//')
echo "path=$FORMAT_PATH" >> $GITHUB_OUTPUT
shell: bash

- name: Python lint
run: python ${{ github.action_path }}/lint.py "${{ steps.setup.outputs.path }}"
shell: bash

- name: YAML lint
run: |
WORKFLOWS=($(echo "${{ steps.setup.outputs.path }}" | tr ' ' '\n'))
for WORKFLOW in "${WORKFLOWS[@]}"; do
yamllint -f colored -c ${{ github.action_path }}/.yamllint.yml $WORKFLOW
done
shell: bash
working-directory: ${{ github.workspace }}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
25 changes: 25 additions & 0 deletions lint-workflow-v2/tests/fixtures/test-alt.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
name: Lint Test File, DO NOT USE

on:
workflow_dispatch:
inputs: {}

jobs:

test-normal-action:
name: Download Latest
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b

- run: |
echo test
test-local-action:
name: Testing a local action call
runs-on: ubuntu-20.04
steps:
- name: local-action
uses: ./version-bump
File renamed without changes.
55 changes: 55 additions & 0 deletions lint-workflow-v2/tests/fixtures/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
name: crowdin Pull

on:
workflow_dispatch:
inputs: {}
schedule:
- cron: "0 0 * * 5"

jobs:
crowdin-pull:
name: Pull
runs-on: ubuntu-20.04
env:
_CROWDIN_PROJECT_ID: "308189"
steps:
- name: Checkout repo
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v2.3.4

- name: Login to Azure
uses: Azure/logi@77f1b2e3fb80c0e8645114159d17008b8a2e475a
with:
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}

- name: Retrieve secrets
id: retrieve-secrets
env:
KEYVAULT: bitwarden-prod-kv
SECRETS: |
crowdin-api-token
run: |
for i in ${SECRETS//,/ }
do
VALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $i --query value --output tsv)
echo "::add-mask::$VALUE"
echo "$i=$VALUE" >> $GITHUB_OUTPUT
done
- uses: crowdin/github-action@e39093fd75daae7859c68eded4b43d42ec78d8ea # v1.3.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
with:
config: crowdin.yml
crowdin_branch_name: master
upload_sources: false
upload_translations: false
download_translations: true
github_user_name: "github-actions"
github_user_email: "<>"
commit_message: "Autosync the updated translations"
localization_branch_name: crowdin-auto-sync
create_pull_request: true
pull_request_title: "Autosync Crowdin Translations"
pull_request_body: "Autosync the updated translations"
27 changes: 27 additions & 0 deletions lint-workflow-v2/tests/fixtures/test_a.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
name: Lint Test File, DO NOT USE

on:
workflow_dispatch:
inputs: {}

jobs:
call-workflow:
uses: bitwarden/server/.github/workflows/workflow-linter.yml@master

test-normal-action:
name: Download Latest
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b

- run: |
echo test
test-local-action:
name: Testing a local action call
runs-on: ubuntu-20.04
steps:
- name: local-action
uses: ./version-bump
Empty file.
File renamed without changes.
Loading

0 comments on commit 4ca8b81

Please sign in to comment.