Merge pull request #26 from mithro/actions.yml

run-drc-for-cell-gds-using-magic: Add action.yml
diff --git a/.github/workflows/test-docker-image-run-drc-for-cell-gds-using-magic.yml b/.github/workflows/test-docker-image-run-drc-for-cell-gds-using-magic.yml
new file mode 100644
index 0000000..6f72005
--- /dev/null
+++ b/.github/workflows/test-docker-image-run-drc-for-cell-gds-using-magic.yml
@@ -0,0 +1,73 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+name: Test Docker Image for Run DRC for cell GDS (using Magic) Action
+
+on:
+  workflow_dispatch:
+  push:
+  pull_request:
+
+
+permissions:
+  contents: read
+
+
+jobs:
+
+  test:
+    name: Basic Test
+
+    runs-on: ubuntu-latest
+
+    steps:
+
+    - uses: actions/checkout@v2
+
+    - name: Check tests/action-local/action.yml is up to date
+      run: |
+        cd run-drc-for-cell-gds-using-magic
+        make ./tests/action-local/action.yml
+        git diff --exit-code --color=always ./tests/action-local/action.yml
+
+    - uses: ./run-drc-for-cell-gds-using-magic/tests/action-local
+      name: Clean cells should pass.
+      with:
+        top: ./run-drc-for-cell-gds-using-magic/tests/clean
+
+    - uses: ./run-drc-for-cell-gds-using-magic/tests/action-local
+      name: Broken cells is filtered (--known-bad).
+      with:
+        top: ./run-drc-for-cell-gds-using-magic/tests/broken
+        known-bad: sky130_fd_sc_hd__clkdlybuf4s15_1
+
+    - uses: ./run-drc-for-cell-gds-using-magic/tests/action-local
+      name: Broken cells is filtered (--match-cells).
+      with:
+        top: ./run-drc-for-cell-gds-using-magic/tests/broken
+        match-cell-directories: clean_cell
+
+    - uses: ./run-drc-for-cell-gds-using-magic/tests/action-local
+      name: Broken cells should fail.
+      id: broken-should-fail
+      continue-on-error: true
+      with:
+        top: ./run-drc-for-cell-gds-using-magic/tests/broken
+
+    - name: Error on success
+      if: steps.broken-should-fail.outcome != 'failure'
+      run:
+        echo "The action should have failed!"
+        exit 1
diff --git a/run-drc-for-cell-gds-using-magic/.update-test-action-local.py b/run-drc-for-cell-gds-using-magic/.update-test-action-local.py
new file mode 100755
index 0000000..0a2455e
--- /dev/null
+++ b/run-drc-for-cell-gds-using-magic/.update-test-action-local.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020 SkyWater PDK Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import pathlib
+
+__dir__ = pathlib.Path(__file__).parent.resolve()
+
+src_action_yml = __dir__ / 'action.yml'
+dst_action_yml = (__dir__ / 'tests' / 'action-local' / 'action.yml').resolve()
+
+print('Base action.yml file at:', src_action_yml)
+print('Test action.yml file at:', dst_action_yml)
+
+with open(src_action_yml) as f:
+    action_data = f.read()
+
+name = 'run-drc-for-cell-gds-using-magic'
+action_data = action_data.replace(
+    f'image: docker://gcr.io/skywater-pdk/actions/{name}:main',
+    'image: ../../Dockerfile',
+)
+
+action_data = action_data.replace(
+    '\nname:',
+    """
+# WARNING! Don't modify this file, modify the base `action.yml` file and then
+# run `make tests/action-local/action.yml`.
+
+name:""")
+
+with open(dst_action_yml, 'w') as f:
+    f.write(action_data)
diff --git a/run-drc-for-cell-gds-using-magic/Makefile b/run-drc-for-cell-gds-using-magic/Makefile
index fb408e8..ef26bc8 100644
--- a/run-drc-for-cell-gds-using-magic/Makefile
+++ b/run-drc-for-cell-gds-using-magic/Makefile
@@ -16,8 +16,15 @@
 
 TOP_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))/..)
 
+NAME := run-drc-for-cell-gds-using-magic
+
+tests/action-local/action.yml: action.yml .update-test-action-local.py
+	$(TOP_DIR)/$(NAME)/.update-test-action-local.py
+
+.PHONY: tests/action-local/action.yml
+
 README.rst: README.src.rst $(TOP_DIR)/docs/*.rst $(TOP_DIR)/Makefile
-	make -C $(TOP_DIR) run-drc-for-cell-gds-using-magic/README.rst
+	make -C $(TOP_DIR) $(NAME)/README.rst
 
 # Redirect everything to the top directory by default.
 %:
diff --git a/run-drc-for-cell-gds-using-magic/README.rst b/run-drc-for-cell-gds-using-magic/README.rst
index e0ad9d5..7c20f65 100644
--- a/run-drc-for-cell-gds-using-magic/README.rst
+++ b/run-drc-for-cell-gds-using-magic/README.rst
@@ -19,9 +19,7 @@
        - uses: actions/checkout@v2
 
        - name: Run DRC for cell GDS (using Magic)
-         uses: docker://gcr.io/skywater-pdk/actions/run-drc-for-cell-gds-using-magic:latest
-         with:
-           args: --acceptable-errors-file /dev/null --match-directories . --known-bad ''
+         uses: google/skywater-pdk-actions/run-drc-for-cell-gds-using-magic@main
 
 Check the Python file for more documentation on arguments.
 
diff --git a/run-drc-for-cell-gds-using-magic/README.src.rst b/run-drc-for-cell-gds-using-magic/README.src.rst
index 75734ef..52ee987 100644
--- a/run-drc-for-cell-gds-using-magic/README.src.rst
+++ b/run-drc-for-cell-gds-using-magic/README.src.rst
@@ -19,9 +19,7 @@
        - uses: actions/checkout@v2
 
        - name: Run DRC for cell GDS (using Magic)
-         uses: docker://gcr.io/skywater-pdk/actions/run-drc-for-cell-gds-using-magic:latest
-         with:
-           args: --acceptable-errors-file /dev/null --match-directories . --known-bad ''
+         uses: google/skywater-pdk-actions/run-drc-for-cell-gds-using-magic@main
 
 Check the Python file for more documentation on arguments.
 
diff --git a/run-drc-for-cell-gds-using-magic/action.yml b/run-drc-for-cell-gds-using-magic/action.yml
new file mode 100644
index 0000000..46465bd
--- /dev/null
+++ b/run-drc-for-cell-gds-using-magic/action.yml
@@ -0,0 +1,52 @@
+# Copyright 2020 SkyWater PDK Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+name: run-drc-for-cell-gds-using-magic
+description: >-
+  This GitHub action runs Design Rule Checks on all GDS files inside the /cells
+  directory.
+
+inputs:
+  top:
+    description: >-
+        What directory to run the check inside.
+    default: .
+  acceptable-errors-file:
+    description: >-
+        A file containing a list of newline-delimited acceptable DRC errors.
+    default: /dev/null
+  match-cell-directories:
+    description: >-
+        A regex that will match cell names to be checked.
+    default: ^.*$
+  known-bad:
+    description: >-
+        Common separated list of known bad cells that should be ignored.
+    default:
+
+
+runs:
+  using: 'docker'
+  image: docker://gcr.io/skywater-pdk/actions/run-drc-for-cell-gds-using-magic:main
+  args:
+  - --top
+  - ${{ inputs.top }}
+  - --acceptable-errors-file
+  - ${{ inputs.acceptable-errors-file }}
+  - --match-cell-directories
+  - ${{ inputs.match-cell-directories }}
+  - --known-bad
+  - ${{ inputs.known-bad }}
diff --git a/run-drc-for-cell-gds-using-magic/run_all_drc.py b/run-drc-for-cell-gds-using-magic/run_all_drc.py
index 5adcbcd..6811e66 100644
--- a/run-drc-for-cell-gds-using-magic/run_all_drc.py
+++ b/run-drc-for-cell-gds-using-magic/run_all_drc.py
@@ -135,6 +135,13 @@
 
 @click.command()
 @click.option(
+    "-t",
+    "--top",
+    default=".",
+    help="Directory to run the process inside."
+         " Default: Current working directory"
+)
+@click.option(
     "-a",
     "--acceptable-errors-file",
     default="/dev/null",
@@ -143,10 +150,11 @@
 )
 @click.option(
     "-m",
-    "--match-directories",
-    default=".",
-    help="A regex that will match subdirectories under cells/."
-         " Default: . (matches everything.)"
+    "--match-cell-directories",
+    default="^.*$",
+    help="A regex that that will match cell names to be checked (which will"
+         " match subdirectories under cells/)."
+         " Default: ^.*$ (matches everything)"
 )
 @click.option(
     "-b",
@@ -156,12 +164,27 @@
          " thus do not cause a non-zero exit upon failure."
          " Default: empty string (None of them.)"
 )
-def run_all_drc(acceptable_errors_file, match_directories, known_bad):
-    print("Testing cells in directories matching /%s/…" % match_directories)
+def run_all_drc(
+            top,
+            acceptable_errors_file,
+            match_cell_directories,
+            known_bad,
+        ):
+
+    os.chdir(top)
+    print("Testing cells in %s directories matching /%s/…" % (
+        os.getcwd(), match_cell_directories))
 
     global acceptable_errors
-    acceptable_errors_str = open(acceptable_errors_file).read()
-    acceptable_errors = acceptable_errors_str.split("\n")
+    acceptable_errors = []
+    with open(acceptable_errors_file) as f:
+        acceptable_errors += f.read().split("\n")
+
+    cells_dir = "./cells"
+    lib_acceptable_errors_file = os.path.join(cells_dir, 'allowed_drc_errors')
+    if os.path.exists(lib_acceptable_errors_file):
+        with open(lib_acceptable_errors_file) as f:
+            acceptable_errors += f.read().split("\n")
 
     known_bad_list = known_bad.split(",")
 
@@ -169,15 +192,16 @@
     with futures.ThreadPoolExecutor(max_workers=nproc) as executor:
         future_list = []
 
-        cells_dir = "./cells"
         cells = os.listdir(cells_dir)
 
         for cell in cells:
-            if not re.match(match_directories, cell):
+            if not re.fullmatch(match_cell_directories, cell):
                 print("Skipping directory %s…" % cell)
                 continue
 
             cell_dir = os.path.join(cells_dir, cell)
+            if not os.path.isdir(cell_dir):
+                continue
 
             gds_list = list(
                 filter(lambda x: x.endswith(".gds"), os.listdir(cell_dir))
@@ -195,19 +219,23 @@
             total += 1
             cell_name, errors = future.result()
 
-            symbol = "❌"
-            message = "ERROR"
             if len(errors) == 0:
                 successes += 1
                 # This tick is rendered black on all major platforms except for
                 # Microsoft.
                 symbol = "✔\ufe0f"
                 message = "CLEAN"
+            elif cell_name in known_bad_list:
+                symbol = "✘\ufe0f"
+                message = "ERROR (ignored as known bad)"
+            else:
+                symbol = "❌"
+                message = "ERROR"
+                exit_code = 65
+
             print("%-64s %s %s" % (cell_name, symbol, message))
 
             if len(errors) != 0:
-                if cell_name not in known_bad_list:
-                    exit_code = 65
                 for error in errors:
                     print("* %s" % error[0])
                     for line in error[1]:
diff --git a/run-drc-for-cell-gds-using-magic/tests/action-local/action.yml b/run-drc-for-cell-gds-using-magic/tests/action-local/action.yml
new file mode 100644
index 0000000..17f369f
--- /dev/null
+++ b/run-drc-for-cell-gds-using-magic/tests/action-local/action.yml
@@ -0,0 +1,55 @@
+# Copyright 2020 SkyWater PDK Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+# WARNING! Don't modify this file, modify the base `action.yml` file and then
+# run `make tests/action-local/action.yml`.
+
+name: run-drc-for-cell-gds-using-magic
+description: >-
+  This GitHub action runs Design Rule Checks on all GDS files inside the /cells
+  directory.
+
+inputs:
+  top:
+    description: >-
+        What directory to run the check inside.
+    default: .
+  acceptable-errors-file:
+    description: >-
+        A file containing a list of newline-delimited acceptable DRC errors.
+    default: /dev/null
+  match-cell-directories:
+    description: >-
+        A regex that will match cell names to be checked.
+    default: ^.*$
+  known-bad:
+    description: >-
+        Common separated list of known bad cells that should be ignored.
+    default:
+
+
+runs:
+  using: 'docker'
+  image: ../../Dockerfile
+  args:
+  - --top
+  - ${{ inputs.top }}
+  - --acceptable-errors-file
+  - ${{ inputs.acceptable-errors-file }}
+  - --match-cell-directories
+  - ${{ inputs.match-cell-directories }}
+  - --known-bad
+  - ${{ inputs.known-bad }}
diff --git a/run-drc-for-cell-gds-using-magic/tests/broken/cells/allowed_drc_errors b/run-drc-for-cell-gds-using-magic/tests/broken/cells/allowed_drc_errors
new file mode 120000
index 0000000..2cfcf43
--- /dev/null
+++ b/run-drc-for-cell-gds-using-magic/tests/broken/cells/allowed_drc_errors
@@ -0,0 +1 @@
+../../clean/cells/allowed_drc_errors
\ No newline at end of file
diff --git a/run-drc-for-cell-gds-using-magic/tests/broken/cells/broken_cell/sky130_fd_sc_hd__clkdlybuf4s15_1.gds b/run-drc-for-cell-gds-using-magic/tests/broken/cells/broken_cell/sky130_fd_sc_hd__clkdlybuf4s15_1.gds
new file mode 100644
index 0000000..b7e4c16
--- /dev/null
+++ b/run-drc-for-cell-gds-using-magic/tests/broken/cells/broken_cell/sky130_fd_sc_hd__clkdlybuf4s15_1.gds
Binary files differ
diff --git a/run-drc-for-cell-gds-using-magic/tests/broken/cells/broken_cell/sky130_fd_sc_hd__clkdlybuf4s15_2.gds b/run-drc-for-cell-gds-using-magic/tests/broken/cells/broken_cell/sky130_fd_sc_hd__clkdlybuf4s15_2.gds
new file mode 100644
index 0000000..bb1a0d8
--- /dev/null
+++ b/run-drc-for-cell-gds-using-magic/tests/broken/cells/broken_cell/sky130_fd_sc_hd__clkdlybuf4s15_2.gds
Binary files differ
diff --git a/run-drc-for-cell-gds-using-magic/tests/broken/cells/clean_cell/sky130_fd_sc_hd__a211o_1.gds b/run-drc-for-cell-gds-using-magic/tests/broken/cells/clean_cell/sky130_fd_sc_hd__a211o_1.gds
new file mode 100644
index 0000000..d4a081a
--- /dev/null
+++ b/run-drc-for-cell-gds-using-magic/tests/broken/cells/clean_cell/sky130_fd_sc_hd__a211o_1.gds
Binary files differ
diff --git a/run-drc-for-cell-gds-using-magic/tests/broken/cells/clean_cell/sky130_fd_sc_hd__a211o_2.gds b/run-drc-for-cell-gds-using-magic/tests/broken/cells/clean_cell/sky130_fd_sc_hd__a211o_2.gds
new file mode 100644
index 0000000..2e70fa7
--- /dev/null
+++ b/run-drc-for-cell-gds-using-magic/tests/broken/cells/clean_cell/sky130_fd_sc_hd__a211o_2.gds
Binary files differ
diff --git a/run-drc-for-cell-gds-using-magic/tests/broken/cells/clean_cell/sky130_fd_sc_hd__a211o_4.gds b/run-drc-for-cell-gds-using-magic/tests/broken/cells/clean_cell/sky130_fd_sc_hd__a211o_4.gds
new file mode 100644
index 0000000..879002f
--- /dev/null
+++ b/run-drc-for-cell-gds-using-magic/tests/broken/cells/clean_cell/sky130_fd_sc_hd__a211o_4.gds
Binary files differ
diff --git a/run-drc-for-cell-gds-using-magic/tests/clean/cells/a2111o/sky130_fd_sc_hd__a2111o_1.gds b/run-drc-for-cell-gds-using-magic/tests/clean/cells/a2111o/sky130_fd_sc_hd__a2111o_1.gds
new file mode 100644
index 0000000..b4d1193
--- /dev/null
+++ b/run-drc-for-cell-gds-using-magic/tests/clean/cells/a2111o/sky130_fd_sc_hd__a2111o_1.gds
Binary files differ
diff --git a/run-drc-for-cell-gds-using-magic/tests/clean/cells/a2111o/sky130_fd_sc_hd__a2111o_2.gds b/run-drc-for-cell-gds-using-magic/tests/clean/cells/a2111o/sky130_fd_sc_hd__a2111o_2.gds
new file mode 100644
index 0000000..7e32913
--- /dev/null
+++ b/run-drc-for-cell-gds-using-magic/tests/clean/cells/a2111o/sky130_fd_sc_hd__a2111o_2.gds
Binary files differ
diff --git a/run-drc-for-cell-gds-using-magic/tests/clean/cells/a2111o/sky130_fd_sc_hd__a2111o_4.gds b/run-drc-for-cell-gds-using-magic/tests/clean/cells/a2111o/sky130_fd_sc_hd__a2111o_4.gds
new file mode 100644
index 0000000..062a5cb
--- /dev/null
+++ b/run-drc-for-cell-gds-using-magic/tests/clean/cells/a2111o/sky130_fd_sc_hd__a2111o_4.gds
Binary files differ
diff --git a/run-drc-for-cell-gds-using-magic/tests/clean/cells/allowed_drc_errors b/run-drc-for-cell-gds-using-magic/tests/clean/cells/allowed_drc_errors
new file mode 100644
index 0000000..e1e13a9
--- /dev/null
+++ b/run-drc-for-cell-gds-using-magic/tests/clean/cells/allowed_drc_errors
@@ -0,0 +1,3 @@
+All nwells must contain metal-connected N+ taps (nwell.4)
+P-diff distance to N-tap must be < 15.0um (LU.3)
+N-diff distance to P-tap must be < 15.0um (LU.2)
\ No newline at end of file