Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce GitHub Action to install project requirements #139

Merged
merged 2 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .github/actions/install-requirement/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Install Project Requirements
description: Install requirements from a PEP 517 project

inputs:
requirements:
description: "Whitespace-delimited list of project requirements to install."
freakboy3742 marked this conversation as resolved.
Show resolved Hide resolved
required: true
project-root:
description: "The filesystem path to the root of the project to install from; defaults to github.workspace."
default: ${{ github.workspace }}
extra:
description: "Name of the optional dependencies marker; e.g. dev."
required: false
default: ""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking that I'm reading this right - if you don't specify extra as an argument, this manifests as --extra "" in the final arguments, right? Would it be worth gating the --extra argument with an if inputs.extra?

Copy link
Member Author

@rmartin16 rmartin16 May 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default value of extra within the install_requirement.py script is an empty string. So, passing --extra an empty string at the command-line is equivalent to not specifying --extra at all. With that, we can control specifying --extra at the command-line but it's effectively duplicating effort the script already handles.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That said...

         python -m install_requirement ${{ inputs.requirements }} \
-          --extra "${{ inputs.extra }}" \
+          ${{ inputs.extra && format('--extra {0}', inputs.extra) || '' }} \
           --project-root "$(printf -- "%q" "${{ steps.paths.outputs.project-root }}")"

workflow-repo:
# Only needed for PRs in other repos wanting to test new workflow changes before they are merged.
# These inputs should not be specified by another repo on their main branch.
description: "The repo to use to run additional workflows and actions."
default: "beeware/.github"
workflow-repo-ref:
description: "The repo ref to use to run additional workflows and actions."
default: ""

runs:
using: composite
steps:
- name: Checkout ${{ inputs.workflow-repo }}${{ inputs.workflow-repo-ref && format('@{0}', inputs.workflow-repo-ref) || '' }}
uses: actions/checkout@v4.1.6
with:
repository: ${{ inputs.workflow-repo }}
ref: ${{ inputs.workflow-repo-ref }}
path: .github-beeware

- name: Resolve Project Root
id: paths
shell: bash
run: echo "project-root=$(cd "${{ inputs.project-root }}"; pwd -P)" | tee -a ${GITHUB_OUTPUT}

- name: Install Dependencies
shell: bash
run: |
python -m pip install --upgrade pip
python -m pip install --upgrade setuptools build wheel

- name: Install Requirements
working-directory: ./.github-beeware/scripts
shell: bash
run: |
python -m install_requirement ${{ inputs.requirements }} \
${{ inputs.extra && format('--extra "{0}"', inputs.extra) || '' }} \
--project-root "$(printf -- "%q" "${{ steps.paths.outputs.project-root }}")"
68 changes: 68 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,74 @@ jobs:
dist-path: "*/dist/*"
build-subdir: core

test-install-requirements:
name: Install Requirements
needs: pre-commit
runs-on: ${{ matrix.runner-os }}
strategy:
fail-fast: false
matrix:
runner-os: [ macos-latest, windows-latest, ubuntu-latest ]
steps:
- name: Checkout beeware/briefcase
uses: actions/checkout@v4.1.6
with:
repository: beeware/briefcase

- name: Checkout beeware/briefcase to path
uses: actions/checkout@v4.1.6
with:
repository: beeware/briefcase
path: repos/briefcase

- name: Checkout beeware/.github
uses: actions/checkout@v4.1.6
with:
repository: beeware/.github
path: repos/.github-beeware

- name: Set up Python
uses: actions/setup-python@v5.1.0
with:
python-version: "3.x"

- name: Test Install Requirements with Path
uses: ./repos/.github-beeware/.github/actions/install-requirement
with:
requirements: "pre-commit tox"
extra: "dev"
project-root: "repos/briefcase"

- name: Test Install Requirements with Extra
uses: ./repos/.github-beeware/.github/actions/install-requirement
with:
requirements: "coverage"
extra: "dev"

- name: Test Install Requirements
uses: ./repos/.github-beeware/.github/actions/install-requirement
with:
requirements: "cookiecutter"

- name: Verify Requirements Installed
run: |
if ! python -m pip list | grep tox; then
echo '::error::Failed to install tox'
exit 1
fi
if ! python -m pip list | grep pre-commit; then
echo '::error::Failed to install pre-commit'
exit 1
fi
if ! python -m pip list | grep coverage; then
echo '::error::Failed to install coverage'
exit 1
fi
if ! python -m pip list | grep cookiecutter; then
echo '::error::Failed to install cookiecutter'
exit 1
fi

test-verify-projects-briefcase:
name: Verify Project
needs: [ pre-commit, test-package-python ]
Expand Down
11 changes: 6 additions & 5 deletions scripts/install_requirement.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
# Install one or more PEP 517 project defined requirements
#
# positional arguments:
# requirements List of project requirements to install. Any project
# requirements that start with any of these values will
# be installed. For instance, including 'pytest' in this
# list would install both pytest and pytest-xdist.
# requirements Whitespace-delimited list of project requirements to install.
#
# options:
# -h, --help show this help message and exit
Expand Down Expand Up @@ -141,10 +138,11 @@ def gather_requirements(

def install_requirements(requirements: list[Requirement]):
"""Install requirements from PyPI."""
installed_reqs = []
for requirement in requirements:
extras = f"[{','.join(requirement.extras)}]" if requirement.extras else ""
requirement_str = f"{requirement.name}{extras}{requirement.specifier}"
print(f"Installing {requirement_str}...")
print(f"Installing {requirement_str}...", flush=True)
subprocess.run(
[
sys.executable,
Expand All @@ -156,6 +154,9 @@ def install_requirements(requirements: list[Requirement]):
],
check=True,
)
installed_reqs.append(requirement_str)

print(f"\nSuccessfully installed:\n {f'{chr(10)} '.join(installed_reqs)}")


def main():
Expand Down
Loading