Adding `modules-pr-backporter` GitHub Action.

A GitHub action which enables pull requests to be successfully merged
into a submodule repository taking into account the multiple versions.

When a pull request is created / updated a new set of branches under
`pr/backports/<pr-number>/<sequence-number>` are created with the
patches in the pull request applied.

For example, if the pull request as `#5` and the repository has branches
`master`, `branch-0.0.2` and `branch-0.0.1` then the GitHub Action would
create;
 * `pr/backports/5/000/master`
 * `pr/backports/5/000/branch-0.0.2`
 * `pr/backports/5/000/branch-0.0.1`

When a pull request is ready to be merged, the `ready-to-merge` label
is added. The GitHub action then makes the
`pr/backports/<pr-number>/<sequence-number>/<branch-name>` branches
the repositories `<branch-name>`. For example;
 * `pr/backports/<pr-number>/<sequence-number>/master`
   becomes `/master`
 * `pr/backports/<pr-number>/<sequence-number>/branch-0.0.2`
   becomes `/branch-0.0.2`

Signed-off-by: Tim 'mithro' Ansell <tansell@google.com>
Signed-off-by: Tim 'mithro' Ansell <me@mith.ro>
Signed-off-by: Ahmed Ghazy <ax3ghazy@aucegypt.edu>
Signed-off-by: Amr Gouhar <aagouhar@efabless.com>
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a81c8ee
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,138 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+#   For a library or package, you might want to ignore these files since the code is
+#   intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+#   However, in case of collaboration, if having platform-specific dependencies or dependencies
+#   having no cross-platform support, pipenv may install dependencies that don't work, or not
+#   install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..ad3f0c8
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "third_party/make-env"]
+	path = third_party/make-env
+	url = https://github.com/SymbiFlow/make-env.git
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..ea70201
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,16 @@
+# This is the list of SkyWater PDK's significant contributors.
+#
+# This does not necessarily list everyone who has contributed code,
+# especially since many employees of one corporation may be contributing.
+# To see the full list of contributors, see the revision history in
+# source control.
+
+# Companies
+Google LLC
+efabless corporation
+The American University in Cairo
+
+# Individuals
+tansell@google.com, me@mith.ro, https://github.com/mithro (Tim 'mithro' Ansell)
+ax3ghazy@aucegypt.edu, https://github.com/ax3ghazy (Ahmed Ghazy)
+aagouhar@efabless.com, https://github.com/agorararmard (Amr Gouhar)
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..fb071b6
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,91 @@
+# 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
+
+# The top directory where environment will be created.
+TOP_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
+
+# A pip `requirements.txt` file.
+# https://pip.pypa.io/en/stable/reference/pip_install/#requirements-file-format
+REQUIREMENTS_FILE := requirements.txt
+
+# A conda `environment.yml` file.
+# https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html
+ENVIRONMENT_FILE := environment.yml
+
+$(TOP_DIR)/third_party/make-env/conda.mk: $(TOP_DIR)/.gitmodules
+	cd $(TOP_DIR); git submodule update --init third_party/make-env
+
+-include $(TOP_DIR)/third_party/make-env/conda.mk
+
+.DEFAULT_GOAL := all
+
+FULL_VERSION := $(shell git describe --long)
+TAG_VERSION  := $(firstword $(subst -, ,$(FULL_VERSION)))
+
+RST_SRC = $(shell find -name *.src.rst)
+RST_OUT = $(RST_SRC:.src.rst=.rst)
+
+%.rst: %.src.rst $(TOP_DIR)/docs/*.rst Makefile | $(CONDA_ENV_PYTHON)
+	@rm -f $@
+	$(IN_CONDA_ENV) rst_include include $< - \
+		| sed \
+			-e's@|TAG_VERSION|@$(TAG_VERSION)@g' \
+			-e's@:ref:`Versioning Information`@`Versioning Information <docs/versioning.rst>`_@g' \
+			-e's@:ref:`Known Issues`@`Known Issues <docs/known_issues.rst>`_@g' \
+			-e's@.. warning::@*Warning*@g' \
+		> $@
+
+update-rst: $(RST_OUT)
+	@echo Found $(RST_SRC) source files.
+
+
+COPYRIGHT_HOLDER := SkyWater PDK Authors
+FIND := find . -path ./env -prune -o -path ./.git -prune -o -path ./third_party -prune -o
+ADDLICENSE := addlicense -f ./docs/license_header.txt
+fix-licenses:
+	@# Makefiles
+	@$(FIND) -type f -name Makefile -exec $(ADDLICENSE) $(ADDLICENSE_EXTRA) -v \{\} \+
+	@$(FIND) -type f -name \*.mk -exec $(ADDLICENSE) $(ADDLICENSE_EXTRA) -v \{\} \+
+	@# Scripting files
+	@$(FIND) -type f -name \*.sh -exec $(ADDLICENSE) $(ADDLICENSE_EXTRA) -v \{\} \+
+	@$(FIND) -type f -name \*.py -exec $(ADDLICENSE) $(ADDLICENSE_EXTRA) -v \{\} \+
+	@# Configuration files
+	@$(FIND) -type f -name \*.yml  -exec $(ADDLICENSE) $(ADDLICENSE_EXTRA) -v \{\} \+
+
+.PHONY: fix-licenses
+
+check-licenses:
+	@make --no-print-directory ADDLICENSE_EXTRA=--check fix-licenses
+
+.PHONY: check-licenses
+
+lint-python: | $(CONDA_ENV_PYTHON)
+	@echo "Found python files:"
+	@$(FIND) -type f -name *.py -print | sed -e's/^/  /'
+	@echo
+	@$(IN_CONDA_ENV) $(FIND) -type f -name *.py -exec flake8 \{\} \+ || echo
+	@$(IN_CONDA_ENV) $(FIND) -type f -name *.py -exec flake8 --quiet --count --statistics \{\} \+
+
+.PHONY: lint-python
+
+check: check-licenses lint-python
+	@true
+
+all: README.rst
+	@true
+
+
+.PHONY: all
diff --git a/README.md b/README.md
deleted file mode 100644
index d68ee16..0000000
--- a/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-# pull-request-merger-action
-This is a Pull Request Merger Action that works on repos with release branch structure. This will overwrite the master branch to match the latest release branch everytime.
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..56b6491
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,87 @@
+skywater-pdk related GitHub Actions
+===================================
+
+.. image:: https://img.shields.io/github/license/google/skywater-pdk-actions
+   :alt: GitHub license - Apache 2.0
+   :target: https://github.com/google/skywater-pdk-actions
+
+.. image:: https://img.shields.io/github/v/tag/google/skywater-pdk-actions?include_prereleases&sort=semver
+   :alt: Latest GitHub tag (including pre-releases)
+   :target: https://gitHub.com/google/skywater-pdk-actions/commit/
+
+.. image:: https://img.shields.io/github/commits-since/google/skywater-pdk-actions/v0.0
+   :alt: GitHub commits since latest release (v0.0)
+   :target: https://gitHub.com/google/skywater-pdk-actions/commit/
+
+This repository contains the GitHub actions uses with the
+`Google skywater-pdk <https://github.com/google/skywater-pdk>`__ and
+`related modules <https://github.com/google?q=skywater-pdk&type=&language=>`__.
+
+.. image:: https://github.com/google/skywater-pdk/raw/master/docs/_static/skywater-pdk-logo.png
+   :alt: Google + SkyWater Logo Image
+   :align: center
+   :target: https://github.com/google/skywater-pdk
+   :width: 80%
+
+Actions
+=======
+
+Modules Related
+---------------
+
+```modules-pr-backporter`` <./modules-pr-backporter>`__
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``modules-pr-backporter`` action is used on the
+`SkyWater modules <https://github.com/google?q=skywater-pdk-libs>`__
+(such as the
+`standard cells <https://github.com/google?q=skywater-pdk-libs-sky130_fd_sc>`__)
+to enable automatic backporting of pull requests to older released
+versions.
+
+```modules-roller`` <./modules-roller>`__
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``modules-roller`` action is used by
+`the primary SkyWater PDK repo <https://github.com/google/skywater-pdk>`__
+to automatically generate pull requests which update the GitHub submodules when
+new changes are added to them.
+
+CI Related
+----------
+
+-  TODO
+
+Resources
+=========
+
+The latest SkyWater SKY130 PDK design resources can be viewed at the following locations:
+
+* `On Github @ google/skywater-pdk <https://github.com/google/skywater-pdk>`_
+* `Google CodeSearch interface @ https://cs.opensource.google/skywater-pdk <https://cs.opensource.google/skywater-pdk>`_
+* `foss-eda-tools.googlesource.com/skywater-pdk <https://foss-eda-tools.googlesource.com/skywater-pdk/>`_
+
+License
+=======
+
+The SkyWater Open Source PDK GitHub actions are released under the
+`Apache 2.0 license <https://github.com/google/skywater-pdk/blob/master/LICENSE>`_.
+
+The copyright details (which should also be found at the top of every file) are;
+
+::
+
+   Copyright 2021 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
+
+       http://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.
+
diff --git a/README.src.rst b/README.src.rst
new file mode 100644
index 0000000..2be8b06
--- /dev/null
+++ b/README.src.rst
@@ -0,0 +1,65 @@
+skywater-pdk related GitHub Actions
+===================================
+
+.. image:: https://img.shields.io/github/license/google/skywater-pdk-actions
+   :alt: GitHub license - Apache 2.0
+   :target: https://github.com/google/skywater-pdk-actions
+
+.. image:: https://img.shields.io/github/v/tag/google/skywater-pdk-actions?include_prereleases&sort=semver
+   :alt: Latest GitHub tag (including pre-releases)
+   :target: https://gitHub.com/google/skywater-pdk-actions/commit/
+
+.. image:: https://img.shields.io/github/commits-since/google/skywater-pdk-actions/|TAG_VERSION|
+   :alt: GitHub commits since latest release (|TAG_VERSION|)
+   :target: https://gitHub.com/google/skywater-pdk-actions/commit/
+
+This repository contains the GitHub actions uses with the
+`Google skywater-pdk <https://github.com/google/skywater-pdk>`__ and
+`related modules <https://github.com/google?q=skywater-pdk&type=&language=>`__.
+
+.. image:: https://github.com/google/skywater-pdk/raw/master/docs/_static/skywater-pdk-logo.png
+   :alt: Google + SkyWater Logo Image
+   :align: center
+   :target: https://github.com/google/skywater-pdk
+   :width: 80%
+
+Actions
+=======
+
+Modules Related
+---------------
+
+```modules-pr-backporter`` <./modules-pr-backporter>`__
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``modules-pr-backporter`` action is used on the
+`SkyWater modules <https://github.com/google?q=skywater-pdk-libs>`__
+(such as the
+`standard cells <https://github.com/google?q=skywater-pdk-libs-sky130_fd_sc>`__)
+to enable automatic backporting of pull requests to older released
+versions.
+
+```modules-roller`` <./modules-roller>`__
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``modules-roller`` action is used by
+`the primary SkyWater PDK repo <https://github.com/google/skywater-pdk>`__
+to automatically generate pull requests which update the GitHub submodules when
+new changes are added to them.
+
+CI Related
+----------
+
+-  TODO
+
+Resources
+=========
+
+The latest SkyWater SKY130 PDK design resources can be viewed at the following locations:
+
+* `On Github @ google/skywater-pdk <https://github.com/google/skywater-pdk>`_
+* `Google CodeSearch interface @ https://cs.opensource.google/skywater-pdk <https://cs.opensource.google/skywater-pdk>`_
+* `foss-eda-tools.googlesource.com/skywater-pdk <https://foss-eda-tools.googlesource.com/skywater-pdk/>`_
+
+
+.. include:: docs/license.rst
diff --git a/action.yml b/action.yml
new file mode 100644
index 0000000..73349fc
--- /dev/null
+++ b/action.yml
@@ -0,0 +1,29 @@
+# Copyright 2021 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: 'Skywater PDK Libraries Pull Request Merger on Release Branches'
+description: 'This is a Pull Request Merger Action that works on repos with release branch structure.'
+runs:
+  using: "composite"
+  steps:
+    - name: Get External Path Name
+      run: echo "EXTERNAL_PATH=$(cd $GITHUB_WORKSPACE/../ && pwd)" >> $GITHUB_ENV
+      shell: bash
+    - name: Run The Pull Request Merger
+      run: |
+        cd $GITHUB_WORKSPACE
+        python3 ${{ github.action_path }}/modules-pr-backporter/library_multi_pull_requests.py 1 $GITHUB_REPOSITORY 2 ${{ github.token }} 3 $EXTERNAL_PATH
+      shell: bash
diff --git a/docs/code-of-conduct.rst b/docs/code-of-conduct.rst
new file mode 100644
index 0000000..3c58179
--- /dev/null
+++ b/docs/code-of-conduct.rst
@@ -0,0 +1,68 @@
+Google Open Source Community Guidelines
+---------------------------------------
+
+.. community_guidelines_text
+
+At Google, we recognize and celebrate the creativity and collaboration
+of open source contributors and the diversity of skills, experiences,
+cultures, and opinions they bring to the projects and communities they
+participate in.
+
+Every one of Google's open source projects and communities are inclusive
+environments, based on treating all individuals respectfully, regardless
+of gender identity and expression, sexual orientation, disabilities,
+neurodiversity, physical appearance, body size, ethnicity, nationality,
+race, age, religion, or similar personal characteristic.
+
+We value diverse opinions, but we value respectful behavior more.
+
+Respectful behavior includes:
+
+-  Being considerate, kind, constructive, and helpful.
+-  Not engaging in demeaning, discriminatory, harassing, hateful,
+   sexualized, or physically threatening behavior, speech, and imagery.
+-  Not engaging in unwanted physical contact.
+
+Some Google open source projects
+`may adopt <https://opensource.google/docs/releasing/preparing/#conduct>`__
+an explicit project code of conduct, which may have additional detailed
+expectations for participants. Most of those projects will use our
+`modified Contributor Covenant <https://opensource.google/docs/releasing/template/CODE_OF_CONDUCT/>`__.
+
+Resolve peacefully
+~~~~~~~~~~~~~~~~~~
+
+We do not believe that all conflict is necessarily bad; healthy debate
+and disagreement often yields positive results. However, it is never
+okay to be disrespectful.
+
+If you see someone behaving disrespectfully, you are encouraged to
+address the behavior directly with those involved. Many issues can be
+resolved quickly and easily, and this gives people more control over the
+outcome of their dispute. If you are unable to resolve the matter for
+any reason, or if the behavior is threatening or harassing, report it.
+We are dedicated to providing an environment where participants feel
+welcome and safe.
+
+Reporting problems
+~~~~~~~~~~~~~~~~~~
+
+Some Google open source projects may adopt a project-specific code of
+conduct. In those cases, a Google employee will be identified as the
+Project Steward, who will receive and handle reports of code of conduct
+violations. In the event that a project hasn’t identified a Project
+Steward, you can report problems by emailing opensource@google.com.
+
+We will investigate every complaint, but you may not receive a direct
+response. We will use our discretion in determining when and how to
+follow up on reported incidents, which may range from not taking action
+to permanent expulsion from the project and project-sponsored spaces. We
+will notify the accused of the report and provide them an opportunity to
+discuss it before any action is taken. The identity of the reporter will
+be omitted from the details of the report supplied to the accused. In
+potentially harmful situations, such as ongoing harassment or threats to
+anyone's safety, we may take action without notice.
+
+*This document was adapted from the*
+`IndieWeb Code of Conduct <https://indieweb.org/code-of-conduct>`_
+*and can also be found at* <https://opensource.google/conduct/>.
diff --git a/docs/contributing.rst b/docs/contributing.rst
new file mode 100644
index 0000000..14f6b0f
--- /dev/null
+++ b/docs/contributing.rst
@@ -0,0 +1,36 @@
+How to Contribute
+=================
+
+We'd love to accept your patches and contributions to this project.
+There are just a few small guidelines you need to follow.
+
+Contributor License Agreement
+-----------------------------
+
+Contributions to this project must be accompanied by a Contributor
+License Agreement. You (or your employer) retain the copyright to your
+contribution; this simply gives us permission to use and redistribute
+your contributions as part of the project. Head over to
+https://cla.developers.google.com/ to see your current agreements on
+file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already
+submitted one (even if it was for a different project), you probably
+don't need to do it again.
+
+Code reviews
+------------
+
+All submissions, including submissions by project members, require
+review. We use GitHub pull requests for this purpose. Consult `GitHub
+Help <https://help.github.com/articles/about-pull-requests/>`__ for more
+information on using pull requests.
+
+Community Guidelines
+--------------------
+
+This project follows `Google's Open Source Community
+Guidelines <https://opensource.google/conduct/>`__.
+
+.. include:: code-of-conduct.rst
+    :start-after: community_guidelines_text
diff --git a/docs/license.rst b/docs/license.rst
new file mode 100644
index 0000000..59507aa
--- /dev/null
+++ b/docs/license.rst
@@ -0,0 +1,23 @@
+License
+=======
+
+The SkyWater Open Source PDK GitHub actions are released under the
+`Apache 2.0 license <https://github.com/google/skywater-pdk/blob/master/LICENSE>`_.
+
+The copyright details (which should also be found at the top of every file) are;
+
+::
+
+   Copyright 2021 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
+
+       http://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.
diff --git a/docs/license_header.txt b/docs/license_header.txt
new file mode 100644
index 0000000..0deef06
--- /dev/null
+++ b/docs/license_header.txt
@@ -0,0 +1,15 @@
+Copyright 2021 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
diff --git a/environment.yml b/environment.yml
new file mode 100644
index 0000000..2a7b5da
--- /dev/null
+++ b/environment.yml
@@ -0,0 +1,25 @@
+# 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: skywater-pdk-actions
+channels:
+- symbiflow
+- defaults
+dependencies:
+- python=3.8
+- pip
+# Packages installed from PyPI
+- pip:
+  - -r file:requirements.txt
diff --git a/modules-pr-backporter/README.rst b/modules-pr-backporter/README.rst
new file mode 100644
index 0000000..fba6e59
--- /dev/null
+++ b/modules-pr-backporter/README.rst
@@ -0,0 +1,178 @@
+``skywater-pdk-actions`` - ``modules-pr-backporter``
+====================================================
+
+This is a Pull Request Merger Action that works on repos with release
+branch structure. This will overwrite the master branch to match the
+latest release branch everytime.
+
+This is mainly done for the google/skywater-pdk-libs-\* repositories.
+
+Workflow
+========
+
+In collaboration with [@ax3ghazy](https://github.com/ax3ghazy), we
+created this workflow for the Pull Request Merger.
+
+Current Workflow when the action is invoked: - The Action will loop over
+all open PRs and download each as a patch. - The Action will apply the
+patch to all version branches merging upward whenever applying is
+possible. - The Action will reset the master to the latest version
+branch. - The changes will be saved in new branches named as
+``pullrequest/temp/<PR ID>/<sequence number>/<branch name>`` where
+sequence number reflects the number of the latest commit added to this
+PR incremented with each commit to that PR. - If a PR is labeled
+``ready-to-merge``, branch
+``pullrequest/temp/<PR ID>/<sequence number>/<branch name>`` becomes
+``<branch name>`` for all the branches in the repository to which the
+patch applies.
+
+Release branches should follow this structure: branch-*.*.\*
+
+Each branch should have a tag with this strucutre: v*.*.\*
+
+This action should only be invoked in case of a Pull Request. We don’t
+handle corner cases at the moment.
+
+Usage:
+======
+
+In Pull-Request Invoked Workflow, add the following:
+
+.. code:: yml
+
+       steps:
+         - uses: actions/checkout@v2
+           with:
+             ref: master
+             fetch-depth: '50'
+
+         - name: Run The Pull Request Merger
+           uses: agorararmard/skywater-pdk-modules-pull-request-backporter-action@main
+
+Examples
+========
+
+There is an example `here <examples/pull_request_merger.yml>`__
+
+How to Contribute
+=================
+
+We'd love to accept your patches and contributions to this project.
+There are just a few small guidelines you need to follow.
+
+Contributor License Agreement
+-----------------------------
+
+Contributions to this project must be accompanied by a Contributor
+License Agreement. You (or your employer) retain the copyright to your
+contribution; this simply gives us permission to use and redistribute
+your contributions as part of the project. Head over to
+https://cla.developers.google.com/ to see your current agreements on
+file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already
+submitted one (even if it was for a different project), you probably
+don't need to do it again.
+
+Code reviews
+------------
+
+All submissions, including submissions by project members, require
+review. We use GitHub pull requests for this purpose. Consult `GitHub
+Help <https://help.github.com/articles/about-pull-requests/>`__ for more
+information on using pull requests.
+
+Community Guidelines
+--------------------
+
+This project follows `Google's Open Source Community
+Guidelines <https://opensource.google/conduct/>`__.
+
+At Google, we recognize and celebrate the creativity and collaboration
+of open source contributors and the diversity of skills, experiences,
+cultures, and opinions they bring to the projects and communities they
+participate in.
+
+Every one of Google's open source projects and communities are inclusive
+environments, based on treating all individuals respectfully, regardless
+of gender identity and expression, sexual orientation, disabilities,
+neurodiversity, physical appearance, body size, ethnicity, nationality,
+race, age, religion, or similar personal characteristic.
+
+We value diverse opinions, but we value respectful behavior more.
+
+Respectful behavior includes:
+
+-  Being considerate, kind, constructive, and helpful.
+-  Not engaging in demeaning, discriminatory, harassing, hateful,
+   sexualized, or physically threatening behavior, speech, and imagery.
+-  Not engaging in unwanted physical contact.
+
+Some Google open source projects
+`may adopt <https://opensource.google/docs/releasing/preparing/#conduct>`__
+an explicit project code of conduct, which may have additional detailed
+expectations for participants. Most of those projects will use our
+`modified Contributor Covenant <https://opensource.google/docs/releasing/template/CODE_OF_CONDUCT/>`__.
+
+Resolve peacefully
+~~~~~~~~~~~~~~~~~~
+
+We do not believe that all conflict is necessarily bad; healthy debate
+and disagreement often yields positive results. However, it is never
+okay to be disrespectful.
+
+If you see someone behaving disrespectfully, you are encouraged to
+address the behavior directly with those involved. Many issues can be
+resolved quickly and easily, and this gives people more control over the
+outcome of their dispute. If you are unable to resolve the matter for
+any reason, or if the behavior is threatening or harassing, report it.
+We are dedicated to providing an environment where participants feel
+welcome and safe.
+
+Reporting problems
+~~~~~~~~~~~~~~~~~~
+
+Some Google open source projects may adopt a project-specific code of
+conduct. In those cases, a Google employee will be identified as the
+Project Steward, who will receive and handle reports of code of conduct
+violations. In the event that a project hasn’t identified a Project
+Steward, you can report problems by emailing opensource@google.com.
+
+We will investigate every complaint, but you may not receive a direct
+response. We will use our discretion in determining when and how to
+follow up on reported incidents, which may range from not taking action
+to permanent expulsion from the project and project-sponsored spaces. We
+will notify the accused of the report and provide them an opportunity to
+discuss it before any action is taken. The identity of the reporter will
+be omitted from the details of the report supplied to the accused. In
+potentially harmful situations, such as ongoing harassment or threats to
+anyone's safety, we may take action without notice.
+
+*This document was adapted from the*
+`IndieWeb Code of Conduct <https://indieweb.org/code-of-conduct>`_
+*and can also be found at* <https://opensource.google/conduct/>.
+
+License
+=======
+
+The SkyWater Open Source PDK GitHub actions are released under the
+`Apache 2.0 license <https://github.com/google/skywater-pdk/blob/master/LICENSE>`_.
+
+The copyright details (which should also be found at the top of every file) are;
+
+::
+
+   Copyright 2021 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
+
+       http://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.
+
diff --git a/modules-pr-backporter/README.src.rst b/modules-pr-backporter/README.src.rst
new file mode 100644
index 0000000..1a24a3f
--- /dev/null
+++ b/modules-pr-backporter/README.src.rst
@@ -0,0 +1,60 @@
+``skywater-pdk-actions`` - ``modules-pr-backporter``
+====================================================
+
+This is a Pull Request Merger Action that works on repos with release
+branch structure. This will overwrite the master branch to match the
+latest release branch everytime.
+
+This is mainly done for the google/skywater-pdk-libs-\* repositories.
+
+Workflow
+========
+
+In collaboration with [@ax3ghazy](https://github.com/ax3ghazy), we
+created this workflow for the Pull Request Merger.
+
+Current Workflow when the action is invoked: - The Action will loop over
+all open PRs and download each as a patch. - The Action will apply the
+patch to all version branches merging upward whenever applying is
+possible. - The Action will reset the master to the latest version
+branch. - The changes will be saved in new branches named as
+``pullrequest/temp/<PR ID>/<sequence number>/<branch name>`` where
+sequence number reflects the number of the latest commit added to this
+PR incremented with each commit to that PR. - If a PR is labeled
+``ready-to-merge``, branch
+``pullrequest/temp/<PR ID>/<sequence number>/<branch name>`` becomes
+``<branch name>`` for all the branches in the repository to which the
+patch applies.
+
+Release branches should follow this structure: branch-*.*.\*
+
+Each branch should have a tag with this strucutre: v*.*.\*
+
+This action should only be invoked in case of a Pull Request. We don’t
+handle corner cases at the moment.
+
+Usage:
+======
+
+In Pull-Request Invoked Workflow, add the following:
+
+.. code:: yml
+
+       steps:
+         - uses: actions/checkout@v2
+           with:
+             ref: master
+             fetch-depth: '50'
+
+         - name: Run The Pull Request Merger
+           uses: agorararmard/skywater-pdk-modules-pull-request-backporter-action@main
+
+Examples
+========
+
+There is an example `here <examples/pull_request_merger.yml>`__
+
+
+.. include:: ../docs/contributing.rst
+
+.. include:: ../docs/license.rst
diff --git a/modules-pr-backporter/examples/pull_request_merger.yml b/modules-pr-backporter/examples/pull_request_merger.yml
new file mode 100644
index 0000000..d0e73b0
--- /dev/null
+++ b/modules-pr-backporter/examples/pull_request_merger.yml
@@ -0,0 +1,33 @@
+# Copyright 2021 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: CI
+
+on: [push]
+
+jobs:
+  build:
+    if: ${{ github.event.label.name == 'ready-to-merge' }}
+    runs-on: ubuntu-latest
+
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          ref: master
+          fetch-depth: '50'
+
+      - name: Run The Pull Request Backporter
+        uses: google/skywater-pdk-actions/modules-pr-backporter@main
diff --git a/modules-pr-backporter/library_multi_pull_requests.py b/modules-pr-backporter/library_multi_pull_requests.py
new file mode 100644
index 0000000..012a2a4
--- /dev/null
+++ b/modules-pr-backporter/library_multi_pull_requests.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python3
+# 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 os
+import subprocess
+import sys
+from library_submodules import run
+from library_submodules import reset_branches
+from library_submodules import label_exists
+from library_submodules import get_git_root
+from library_submodules import git_fetch
+from library_patch_submodules import library_patch_submodules
+from library_patch_submodules import library_merge_submodules
+from library_patch_submodules import library_clean_submodules
+
+__dir__ = os.path.dirname(__file__)
+
+
+def handle_pull_requests(args):
+    print(args)
+    assert len(args) == 6
+    dmp = args.pop(0)
+    repo_name = args.pop(0)
+    dmp = args.pop(0)
+    access_token = args.pop(0)
+    dmp = args.pop(0)
+    external_path = args.pop(0)
+    print(dmp)
+    print()
+    print()
+
+    git_root = get_git_root()
+
+    git_fetch(git_root)
+    prs_open_url = \
+        'https://api.github.com/repos/{0}/pulls?state=open'.format(repo_name)
+    curl_grep = \
+        "curl -sS {0} | grep -o -E 'pull/[[:digit:]]+'".format(prs_open_url)
+    comp_cmd = "{0} | sed 's/pull\\///g' | sort | uniq".format(curl_grep)
+    all_open_pull_requests = subprocess.check_output(
+        comp_cmd, shell=True).decode('utf-8').split()
+
+    print("All Open Pull Requests: ", all_open_pull_requests)
+    library_clean_submodules(all_open_pull_requests)
+    for pull_request_id in all_open_pull_requests:
+        print()
+        print("Processing:", str(pull_request_id))
+        print('-'*20, flush=True)
+        commit_hash = subprocess.check_output(
+            "git ls-remote origin 'pull/*/head'| grep 'pull/{0}/head'".format(
+                pull_request_id) +
+            " | tail -1 | awk '{ print $1F }'",
+            shell=True).decode('utf-8')
+        print()
+        print("Getting Patch")
+        print()
+        run('wget https://github.com/{0}/pull/{1}.patch'
+            .format(repo_name, pull_request_id))
+        run('mv {0}.patch {1}/'.format(pull_request_id, external_path))
+        patchfile = '{0}/{1}.patch'.format(external_path, pull_request_id)
+        print("Will try to apply: ", patchfile)
+
+        if library_patch_submodules(
+                patchfile, pull_request_id, repo_name, access_token,
+                commit_hash):
+            print()
+            print("Pull Request Handled: ", str(pull_request_id))
+            print('-'*20, flush=True)
+            if label_exists(repo_name, pull_request_id, 'ready-to-merge'):
+                print("PR {0} is now ready to be merged.."
+                      .format(pull_request_id))
+                library_merge_submodules(
+                    pull_request_id, repo_name, access_token)
+        print("Resetting Branches")
+        reset_branches(git_root)
+        print("Reset Branches Done!")
+
+    print('-'*20, flush=True)
+    print("Done Creating PR branches!")
+    print('-'*20, flush=True)
+
+
+if __name__ == "__main__":
+    sys.exit(handle_pull_requests(sys.argv[1:]))
diff --git a/modules-pr-backporter/library_patch_submodules.py b/modules-pr-backporter/library_patch_submodules.py
new file mode 100644
index 0000000..7f53b14
--- /dev/null
+++ b/modules-pr-backporter/library_patch_submodules.py
@@ -0,0 +1,293 @@
+#!/usr/bin/env python3
+# 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 os
+import subprocess
+import sys
+from library_submodules import git
+from library_submodules import out_v
+from library_submodules import previous_v
+from library_submodules import get_sequence_number
+from library_submodules import git_issue_comment
+from library_submodules import git_issue_close
+from library_submodules import get_git_root
+from library_submodules import git_fetch
+from library_submodules import get_lib_versions
+from library_submodules import git_clean
+
+
+__dir__ = os.path.dirname(__file__)
+
+
+def library_patch_submodules(
+        patchfile, pull_request_id, repo_name, access_token, commit_hash):
+
+    assert os.path.exists(patchfile), patchfile
+    assert os.path.isfile(patchfile), patchfile
+    assert pull_request_id.isdigit(), pull_request_id
+
+    print()
+    print()
+    git_root = get_git_root()
+
+    git_fetch(git_root)
+
+    versions = get_lib_versions(git_root)
+    failed = True
+    apply_idx = 0
+    for i, v in enumerate(versions):
+        pv = previous_v(v, versions)
+        ov = out_v(v, versions)
+
+        v_branch = "branch-{}.{}.{}".format(*ov)
+        v_tag = "v{}.{}.{}".format(*ov)
+
+        print()
+        print("Was:", pv, "Now patching", (v_branch, v_tag), "with", patchfile)
+        print('-'*20, flush=True)
+
+        # Get us back to a very clean tree.
+        # git('reset --hard HEAD', git_root)
+        git_clean(git_root)
+
+        # Checkout the right branch
+        git('checkout {0}'.format(v_branch), git_root)
+
+        diff_pos = 'branch-{}.{}.{}'.format(*pv)
+
+        # Update the contents
+        if v == versions[apply_idx]:
+            if git('am {}'.format(patchfile),
+                    git_root, can_fail=True) is False:
+                apply_idx += 1
+                git('am --abort', git_root)
+            failed = False
+            continue
+        # Create the merge commit
+        git('merge {} --no-ff --no-commit --strategy=recursive'
+            .format(diff_pos),
+            git_root)
+        git('commit -C HEAD@{1}', git_root)
+    if failed:
+        return False
+    git('branch -D master', git_root, can_fail=True)
+    git('branch master', git_root)
+
+    print('='*75, flush=True)
+
+    old_git_sequence = int(get_sequence_number(pull_request_id))
+    sequence_increment = 1
+    if old_git_sequence != -1:
+        old_pr_branch = \
+            'pullrequest/temp/{0}/{1}/master'.format(
+                pull_request_id, str(old_git_sequence))
+        git('checkout {0}'.format(old_pr_branch), git_root)
+        internal_patch = subprocess.check_output(
+            'git diff {0}..master'.format(old_pr_branch),
+            shell=True).decode('utf-8').strip()
+        print(internal_patch)
+        print('**********************')
+        if not len(internal_patch):
+            sequence_increment = 0
+        print(sequence_increment)
+    git_sequence = old_git_sequence + sequence_increment
+
+    n_branch_links = ""
+    for i, v in enumerate(versions):
+        ov = out_v(v, versions)
+        v_branch = "branch-{}.{}.{}".format(*ov)
+        v_tag = "v{}.{}.{}".format(*ov)
+        print()
+        print("Now Pushing", (v_branch, v_tag))
+        print('-'*20, flush=True)
+
+        n_branch = 'pullrequest/temp/{0}/{1}/{2}'.format(
+            pull_request_id, str(git_sequence), v_branch)
+        branch_link = "https://github.com/{0}/tree/{1}".format(
+            repo_name, n_branch)
+        n_branch_links += "\n- {0}".format(branch_link)
+        print("Now Pushing", n_branch)
+        if git('push -f origin {0}:{1}'.format(v_branch, n_branch),
+                git_root, can_fail=True) is False:
+            print("""\
+Pull Request {0} is coming from a fork and trying to update the workflow. \
+We will skip it!!! \
+""")
+            return False
+
+    print()
+    n_branch = 'pullrequest/temp/{0}/{1}/master'.format(
+        pull_request_id, str(git_sequence))
+    branch_link = "https://github.com/{0}/tree/{1}".format(repo_name, n_branch)
+    n_branch_links += "\n- {0}".format(branch_link)
+
+    print("Now Pushing", n_branch)
+    print('-'*20, flush=True)
+    if git('push -f origin master:{0}'.format(n_branch),
+            git_root, can_fail=True) is False:
+        print("""\
+Pull Request {0} is coming from a fork and trying to update the workflow. \
+We will skip it!!! \
+""")
+        return False
+
+    if sequence_increment:
+        comment_body = """\
+The latest commit of this PR, commit {0} has been applied to the branches, \
+please check the links here:
+ {1}
+""".format(commit_hash, n_branch_links)
+        git_issue_comment(repo_name,
+                          pull_request_id,
+                          comment_body,
+                          access_token)
+    return True
+
+
+def library_merge_submodules(pull_request_id, repo_name, access_token):
+    print()
+    print()
+    git_root = get_git_root()
+
+    git_fetch(git_root)
+
+    versions = get_lib_versions(git_root)
+    for i, v in enumerate(versions):
+        pv = previous_v(v, versions)
+        ov = out_v(v, versions)
+
+        v_branch = "branch-{}.{}.{}".format(*ov)
+        v_tag = "v{}.{}.{}".format(*ov)
+        git_sequence = int(get_sequence_number(pull_request_id))
+        n_branch = 'pullrequest/temp/{0}/{1}/{2}'\
+                   .format(pull_request_id,
+                           str(git_sequence),
+                           v_branch)
+        print()
+        print("Was:", pv, "Now updating", (v_branch, v_tag), "with", n_branch)
+        print('-'*20, flush=True)
+
+        # Get us back to a very clean tree.
+        # git('reset --hard HEAD', git_root)
+        git_clean(git_root)
+
+        # Checkout the right branch
+        git('checkout {0}'.format(v_branch), git_root)
+        print("Now reseting ", v_branch, " to ", n_branch)
+        git('reset --hard origin/{0}'.format(n_branch), git_root)
+        print("Now Pushing", v_branch)
+        git('push -f origin {0}:{0}'.format(v_branch), git_root)
+        for i in range(git_sequence + 1):
+            git('push origin --delete pullrequest/temp/{0}/{1}/{2}'
+                .format(pull_request_id, str(i), v_branch),
+                git_root)
+
+    git_clean(git_root)
+    n_branch = 'pullrequest/temp/{0}/{1}/master'.format(pull_request_id,
+                                                        str(git_sequence))
+    git('checkout master', git_root)
+    print("Now reseting master to ", n_branch)
+    git('reset --hard origin/{0}'.format(n_branch), git_root)
+    print("Now Pushing", v_branch)
+    git('push -f origin master:master', git_root)
+    for i in range(git_sequence + 1):
+        git('push origin --delete pullrequest/temp/{0}/{1}/master'
+            .format(pull_request_id, str(i)),
+            git_root)
+    git_issue_close(repo_name, pull_request_id, access_token)
+    comment_body = """\
+Thank you for your pull request. This pull request will be closed, because \
+the Pull-Request Merger has successfully applied it internally to all \
+branches.
+"""
+    git_issue_comment(repo_name, pull_request_id, comment_body, access_token)
+
+
+def library_rebase_submodules(pull_request_id):
+    print()
+    print()
+    git_root = get_git_root()
+
+    git_fetch(git_root)
+
+    versions = get_lib_versions(git_root)
+    for i, v in enumerate(versions):
+        pv = previous_v(v, versions)
+        ov = out_v(v, versions)
+
+        v_branch = "branch-{}.{}.{}".format(*ov)
+        v_tag = "v{}.{}.{}".format(*ov)
+        git_sequence = int(get_sequence_number(pull_request_id))
+        n_branch = 'pullrequest/temp/{0}/{1}/{2}'.format(
+            pull_request_id, str(git_sequence), v_branch)
+        print()
+        print("Was:", pv,
+              "Now rebasing ", n_branch,
+              " with ", (v_branch, v_tag))
+        print('-'*20, flush=True)
+
+        # Get us back to a very clean tree.
+        # git('reset --hard HEAD', git_root)
+        git_clean(git_root)
+
+        # Checkout the right branch
+        git('checkout {0}'.format(n_branch), git_root)
+        git('rebase origin/{0}'.format(v_branch), git_root)
+        print("Now Pushing", n_branch)
+        git('push -f origin {0}:{0}'.format(n_branch), git_root)
+
+    git_clean(git_root)
+    n_branch = 'pullrequest/temp/{0}/{1}/master'.format(
+        pull_request_id, str(git_sequence))
+    git('checkout {0}'.format(n_branch), git_root)
+    git('rebase origin/master', git_root)
+    print("Now Pushing", n_branch)
+    git('push -f origin {0}:{0}'.format(n_branch), git_root)
+
+
+def library_clean_submodules(all_open_pull_requests):
+    print()
+    print()
+    print("Cleaning up pull request branches for closed pull requests.")
+    git_root = get_git_root()
+
+    git_fetch(git_root)
+
+    all_branches = subprocess.check_output('git branch -r',
+                                           shell=True).decode('utf-8').split()
+    print("All branchs:", all_branches)
+    for br in all_branches:
+        if "origin/pullrequest/temp/" in br \
+                and br.split('/')[3] not in all_open_pull_requests:
+            print('Deleting ', br)
+            git('push origin --delete {0}'.format(br.split('origin/', 1)[1]),
+                git_root)
+
+
+def main(args):
+    assert len(args) == 5
+    patchfile = os.path.abspath(args.pop(0))
+    pull_request_id = args.pop(0)
+    repo_name = args.pop(0)
+    access_token = args.pop(0)
+    commit_hash = args.pop(0)
+    library_patch_submodules(
+        patchfile, pull_request_id, repo_name, access_token, commit_hash)
+
+
+if __name__ == "__main__":
+    sys.exit(main(sys.argv[1:]))
diff --git a/modules-pr-backporter/library_submodules.py b/modules-pr-backporter/library_submodules.py
new file mode 100644
index 0000000..0cda394
--- /dev/null
+++ b/modules-pr-backporter/library_submodules.py
@@ -0,0 +1,157 @@
+#!/usr/bin/env python3
+# 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 os
+import subprocess
+import sys
+import time
+import requests
+import json
+
+
+def run(cmd, **kw):
+    sys.stdout.flush()
+    sys.stderr.flush()
+    print(cmd, '-'*5, flush=True)
+    subprocess.check_call(cmd, shell=True, stderr=subprocess.STDOUT, **kw)
+    print('-'*5, flush=True)
+    sys.stdout.flush()
+    sys.stderr.flush()
+
+
+DATE = None  # 'Mon Oct 06 16:55:02 2020 -0700'
+
+
+def git(cmd, gitdir, can_fail=False, **kw):
+    env = dict(os.environ)
+    if DATE:
+        env['GIT_AUTHOR_DATE'] = DATE
+        env['GIT_COMMITTER_DATE'] = DATE
+    env['GIT_COMMITTER_NAME'] = "GitHub Actions Bot"
+    env['GIT_COMMITTER_EMAIL'] = 'actions_bot@github.com'
+
+    if 'push' in cmd:
+        cmd += ' --verbose --progress'
+
+    i = 0
+    while True:
+        try:
+            run('git '+cmd, cwd=gitdir, env=env, **kw)
+            break
+        except subprocess.CalledProcessError:
+            if can_fail:
+                return False
+            i += 1
+            if i < 5:
+                time.sleep(10)
+                continue
+            raise
+
+
+def out_v(v, versions):
+    if (0, 0, 0) in versions:
+        return (v[0], v[1], v[2]+1)
+    return v
+
+
+def previous_v(v, versions):
+    assert v in versions, (v, versions)
+    vers = [(0, 0, 0)]+[out_v(x, versions) for x in list(versions)]
+    ov = out_v(v, versions)
+    assert ov in vers, (ov, vers)
+    i = vers.index(ov)
+    assert i > 0, (i, ov, vers)
+    return vers[i-1]
+
+
+def reset_branches(git_root):
+    all_local_branches = subprocess.check_output(
+        'git branch', shell=True).decode('utf-8').split()
+    for branch in all_local_branches:
+        if branch != "*" and not branch.startswith('pullrequest/temp/'):
+            git('checkout {0}'.format(branch), git_root)
+            git('reset --hard origin/{0}'.format(branch), git_root)
+
+
+def get_sequence_number(pull_request_id):
+    git_sequence = -1
+    all_branches = subprocess.check_output(
+        'git branch -r', shell=True).decode('utf-8').split()
+    print("All branchs:", all_branches)
+    git_matching_branches = [br for br in all_branches
+                             if "origin/pullrequest/temp/{0}/"
+                                .format(pull_request_id) in br]
+
+    for matching_branch in git_matching_branches:
+        git_sequence = max(int(matching_branch.split("/")[4]), git_sequence)
+    return git_sequence
+
+
+def label_exists(repo_name, pull_request_id, label):
+    r = requests.get(
+        'https://api.github.com/repos/{0}/issues/{1}/labels'.format(
+            repo_name, pull_request_id))
+    for item in r.json():
+        if item['name'] == label:
+            return True
+    return False
+
+
+def git_issue_comment(repo_name, pull_request_id, body, access_token):
+    url = 'https://api.github.com/repos/{0}/issues/{1}/comments'.format(
+        repo_name, pull_request_id)
+    payload = {'body': body}
+    headers = {'Authorization': 'token {0}'.format(access_token)}
+    requests.post(url, data=json.dumps(payload), headers=headers)
+
+
+def git_issue_close(repo_name, pull_request_id, access_token):
+    url = 'https://api.github.com/repos/{0}/issues/{1}'.format(
+        repo_name, pull_request_id)
+    payload = {'state': 'closed'}
+    headers = {'Authorization': 'token {0}'.format(access_token)}
+    requests.post(url, data=json.dumps(payload), headers=headers)
+
+
+def get_git_root():
+    return subprocess.check_output(
+        'git rev-parse --show-toplevel', shell=True).decode('utf-8').strip()
+
+
+def git_fetch(git_root):
+    print()
+    print()
+    git('fetch origin', git_root)
+    git('fetch origin --tags', git_root)
+    git('status', git_root)
+    print('-'*20, flush=True)
+
+
+def get_lib_versions(git_root):
+    tags = subprocess.check_output('git tag -l', shell=True, cwd=git_root)
+
+    tags = tags.decode('utf-8')
+
+    versions = [tuple(int(i) for i in v[1:].split('.')) for v in tags.split()]
+    if (0, 0, 0) in versions:
+        versions.remove((0, 0, 0))
+    return versions
+
+
+def git_clean(git_root):
+    git('clean -f', git_root)
+    git('clean -x -f', git_root)
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..58d13b0
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,5 @@
+flake8
+
+# rst_include tool as GitHub doesn't support `.. include::` when rendering
+# previews.
+rst_include
diff --git a/third_party/make-env b/third_party/make-env
new file mode 160000
index 0000000..9b07ad2
--- /dev/null
+++ b/third_party/make-env
@@ -0,0 +1 @@
+Subproject commit 9b07ad2bb62fbf8af789c9e4669715c974b4912d