Skip to content

Commit

Permalink
Upgrading versions and adding Continuous Integration and Delivery
Browse files Browse the repository at this point in the history
  • Loading branch information
chris-zen committed Aug 16, 2024
1 parent e8005db commit cb4220f
Show file tree
Hide file tree
Showing 16 changed files with 594 additions and 145 deletions.
8 changes: 8 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.github
.ruff_cache/
.venv/
data/
dist/
docs/
example/
oncodrivefml.egg-info/
201 changes: 201 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
name: Build and Publish

on:
push:
tags:
- "**"
branches:
- "**"

permissions:
contents: read

env:
TERM: xterm

jobs:
packages-build:
name: Build packages
runs-on: ubuntu-latest
env:
RUFF_FORMAT: github

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.8
uses: actions/setup-python@v3
with:
python-version: "3.8"

- name: Prepare virtual environment
run: make create-env

- name: Check format
run: |
make check-format || true
BOLDRED=$(tput bold && tput setaf 1)
RESET=$(tput sgr0)
echo "${BOLDRED}==> We won't fail on formatting errors for the time being, but we will in the future.${RESET}"
- name: Check lint
run: |
make check-lint || true
BOLDRED=$(tput bold && tput setaf 1)
RESET=$(tput sgr0)
echo "${BOLDRED}==> We won't fail on lint errors for the time being, but we will in the future.${RESET}"
- name: Build packages
run: make build-dist

- name: Upload packages
uses: actions/upload-artifact@v4
with:
name: python-packages
path: dist

docker-build:
name: Build Docker image
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.8
uses: actions/setup-python@v3
with:
python-version: "3.8"

- name: Prepare virtual environment
run: make create-env

- name: Check Dockerfile
run: make check-docker

- name: Build Docker image
run: make build-image

# TODO: Enable this when we figure out how to run it without having to download several Gigabytes of data.
# - name: Test Docker image
# run: make run-example

docs-build:
name: Build documentation
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.8
uses: actions/setup-python@v3
with:
python-version: "3.8"

- name: Check version matching the tag
run: make docs

- name: Upload documentation
uses: actions/upload-artifact@v4
with:
name: documentation
path: docs/build

check-version:
name: Check version
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.8
uses: actions/setup-python@v3
with:
python-version: "3.8"

- name: Prepare virtual environment
run: make create-env

- name: Check version matching the tag
run: make check-version

docs-publish:
name: Publish documentation
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
env:
RTD_USERNAME: ${{ secrets.RTD_USERNAME }}

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.8
uses: actions/setup-python@v3
with:
python-version: "3.8"

- name: Prepare virtual environment
run: make create-env

- name: Download documentation
uses: actions/download-artifact@v4
with:
name: documentation

# TODO: Add a step to publish the docs to ReadTheDocs

packages-publish:
name: Publish packages
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
env:
PYPI_USERNAME: ${{ secrets.PYPI_USERNAME }}
needs:
- check-version
- packages-build
- docker-build

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.8
uses: actions/setup-python@v3
with:
python-version: "3.8"

- name: Prepare virtual environment
run: make create-env

- name: Download packages
uses: actions/download-artifact@v4
with:
name: python-packages

- name: Publish to PyPI
if: ${{ env.PYPI_USERNAME != '' }}
env:
PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: make publish-dist

docker-push:
name: Push Docker image
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
needs:
- check-version
- packages-build
- docker-build

steps:
- if: ${{ env.DOCKER_USERNAME != '' }}
uses: actions/checkout@v3

- name: Login to DockerHub
if: ${{ env.DOCKER_USERNAME != '' }}
run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin

- name: Push Docker image
if: ${{ env.DOCKER_USERNAME != '' }}
run: make push-image
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,8 @@ example/cdsOriginal
docs/build

# External users tests
external_checks
external_checks

.ruff_cache/
.venv
data/
2 changes: 2 additions & 0 deletions .hadolint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ignored:
- DL3003
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.8
20 changes: 20 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM python:3.8-slim

# hadolint ignore=DL3013
RUN pip install --no-cache-dir --upgrade pip

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests \
build-essential=12.9 \
zlib1g-dev=1:1.2.13.dfsg-1 && \
rm -rf /var/lib/apt/lists/*

# hadolint ignore=DL3042
RUN --mount=type=cache,target=/root/.cache/pip \
--mount=type=bind,target=/project,rw \
cd /project && \
pip install .

ENTRYPOINT [ "/usr/local/bin/oncodrivefml" ]
148 changes: 148 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
ROOT_DIR := $(shell echo $(dir $(lastword $(MAKEFILE_LIST))) | sed 's|/*$$||')

DOCS_DIR := $(ROOT_DIR)/docs
VENV_DIR := $(ROOT_DIR)/.venv

VERSION ?= $(shell $(VENV_DIR)/bin/python -c 'from oncodrivefml import __version__; print(f"{__version__}")')

GIT_TAG_OR_SHA = $(shell git describe --tags --exact-match 2>/dev/null || git rev-parse --short HEAD)

IMAGE_TAG ?= $(VERSION)
IMAGE := bbglab/oncodrivefml:$(IMAGE_TAG)

BOLDRED := $(shell tput bold && tput setaf 1)
BOLDGREEN := $(shell tput bold && tput setaf 2)
BOLDYELLOW := $(shell tput bold && tput setaf 3)
WHITE := $(shell tput sgr0 && tput setaf 7)
RESET := $(shell tput sgr0)


.PHONY: help
help:
@echo "$(BOLDYELLOW)Available targets:$(RESET)"
@echo
@echo "$(BOLDGREEN) checks $(WHITE)-> Run all the checks (format and lint)"
@echo "$(BOLDGREEN) check-format $(WHITE)-> Check for formatting errors"
@echo "$(BOLDGREEN) check-lint $(WHITE)-> Check for lint errors"
@echo "$(BOLDGREEN) check-docker $(WHITE)-> Check the Dockerfile"
@echo "$(BOLDGREEN) format $(WHITE)-> Format source code"
@echo "$(BOLDGREEN) build-dist $(WHITE)-> Build source and wheel distribution files"
@echo "$(BOLDGREEN) install $(WHITE)-> Install the packages in editable mode"
@echo "$(BOLDGREEN) create-env $(WHITE)-> Create a virtual environment"
@echo "$(BOLDGREEN) remove-env $(WHITE)-> Remove the virtual environment"
@echo "$(BOLDGREEN) build-image $(WHITE)-> Build the Docker image"
@echo "$(BOLDGREEN) push-image $(WHITE)-> Push the Docker image into DockerHub"
@echo "$(BOLDGREEN) docs $(WHITE)-> Generate the documentation"
@echo "$(BOLDGREEN) run-example $(WHITE)-> Run the included example using the Docker image"
@echo "$(BOLDGREEN) clean $(WHITE)-> Clean the working directory (build files, virtual environments, caches)"
@echo "$(RESET)"

$(VENV_DIR):
@echo "$(BOLDYELLOW)Preparing virtual environment ...$(RESET)"
python -m venv $(VENV_DIR)
$(VENV_DIR)/bin/pip install -U pip ruff setuptools wheel build twine
@echo "$(BOLDGREEN)==> Success!$(RESET)"

.PHONY: checks
checks: check-format check-lint check-docker

.PHONY: check-format
check-format: $(VENV_DIR)
@echo "$(BOLDGREEN)Checking code format ...$(RESET)"
$(VENV_DIR)/bin/ruff format --check
@echo "$(BOLDGREEN)==> Success!$(RESET)"

.PHONY: check-lint
check-lint: $(VENV_DIR)
@echo "$(BOLDGREEN)Checking lint ...$(RESET)"
$(VENV_DIR)/bin/ruff check
@echo "$(BOLDGREEN)==> Success!$(RESET)"

.PHONY: check-docker
check-docker:
@echo "$(BOLDGREEN)Checking Dockerfile ...$(RESET)"
docker run --rm -i \
-v $$(pwd):/project \
hadolint/hadolint hadolint \
--config /project/.hadolint.yaml \
/project/Dockerfile
@echo "$(BOLDGREEN)==> Success!$(RESET)"

.PHONY: check-version
check-version: $(VENV_DIR)
@echo "$(BOLDGREEN)Checking that the version matches the tag ...$(RESET)"
@if [ "$(VERSION)" != "$(GIT_TAG_OR_SHA)" ]; then \
echo "$(BOLDRED)==> Version $(BOLDYELLOW)$(VERSION)$(BOLDRED) doesn't match the git tag $(BOLDYELLOW)$(GIT_TAG_OR_SHA)$(BOLDRED) !!!$(RESET)"; \
echo "$(BOLDRED)==> Please update the $(BOLDYELLOW)__version__$(BOLDRED) in $(BOLDYELLOW)oncodrivefml/__init__.py$(BOLDRED) and re-create the tag.$(RESET)"; \
exit 1; \
fi
@echo "$(BOLDGREEN)==> Success!$(RESET)"

.PHONY: format
format: $(VENV_DIR)
@echo "$(BOLDGREEN)Formatting code ...$(RESET)"
$(VENV_DIR)/bin/ruff format

.PHONY: build-dist
build-dist: $(VENV_DIR)
@echo "$(BOLDGREEN)Building packages ...$(RESET)"
$(VENV_DIR)/bin/python -m build

.PHONY: publish-dist
publish-dist: $(VENV_DIR)
@echo "$(BOLDGREEN)Publishing OncodriveFML $(BOLDYELLOW)$(VERSION)$(BOLDGREEN) to PyPI ...$(RESET)"
@[[ -z "$(PYPI_USERNAME)" || -z "$(PYPI_PASSWORD)" ]] && (echo "$(BOLDRED)==> Missing PyPI credentials !!!$(RESET)"; exit 1)
$(VENV_DIR)/bin/twine upload \
--username $(PYPI_USERNAME) \
--password $(PYPI_PASSWORD) \
dist/*

.PHONY: install
install: $(VENV_DIR)
pip install -e .

.PHONY: create-env
create-env: $(VENV_DIR)

.PHONY: remove-env
remove-env:
@echo "$(BOLDGREEN)Removing virtual environment ...$(RESET)"
rm -rf $(VENV_DIR)

.PHONY: build-image
build-image:
@echo "$(BOLDGREEN)Building Docker image $(BOLDYELLOW)$(IMAGE)$(BOLDGREEN) ...$(RESET)"
docker build --progress=plain -t $(IMAGE) .
@echo "$(BOLDGREEN)==> Success!$(RESET)"

.PHONY: build-image
push-image:
@echo "$(BOLDGREEN)Pushing the Docker image into the DockerHub ...$(RESET)"
docker push $(IMAGE)
@echo "$(BOLDGREEN)==> Success!$(RESET)"

.PHONY: docs
docs: $(VENV_DIR)
@if ! which $(VENV_DIR)/bin/sphinx-build > /dev/null; then \
$(VENV_DIR)/bin/pip install -r optional-requirements.txt; \
fi
(source $(VENV_DIR)/bin/activate; make -C $(DOCS_DIR) html)

.PHONY: run-example
run-example:
@echo "$(BOLDGREEN)Running example ...$(RESET)"
docker run --rm -i \
--workdir /example \
-e BGDATA_LOCAL=/data \
-v $$(pwd)/data:/data \
-v $$(pwd)/example:/example \
oncodrivefml:latest \
-i paad.txt.gz -e cds.tsv.gz --signature-correction wx --seed 123 --force
@echo "$(BOLDGREEN)==> Success!$(RESET)"

.PHONY: clean
clean:
@echo "$(BOLDGREEN)Cleaning the repository ...$(RESET)"
rm -rf ./oncodrivefml.egg-info ./dist $(VENV_DIR) ./.ruff_cache ./.eggs $(DOCS_DIR)/build
find oncodrivefml \( -name '*.c' -o -name '*.so' \) -type f -exec rm {} +
find . -name "__pycache__" -type d -exec rm -r {} +
Loading

0 comments on commit cb4220f

Please sign in to comment.