From 67edafa0062582e4eec47c59d05a7b4b2429f435 Mon Sep 17 00:00:00 2001 From: MarkKoz <1515135+MarkKoz@users.noreply.github.com> Date: Mon, 30 May 2022 23:31:12 -0700 Subject: Automatically determine the package version Use the HEAD commit's date as the package's version. Append the number of commits made on the same date as HEAD to ensure multiple releases on the same date still have unique versions. --- scripts/version.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 scripts/version.py (limited to 'scripts/version.py') diff --git a/scripts/version.py b/scripts/version.py new file mode 100644 index 0000000..9076b93 --- /dev/null +++ b/scripts/version.py @@ -0,0 +1,34 @@ +import datetime +import subprocess + +__all__ = ("get_version",) + + +def get_version() -> str: + """ + Return a version based on the HEAD commit's date. + + The format is 'year.month.day.commits' and is compliant with PEP 440. 'commits' is the amount of + commits made on the same date as HEAD, excluding HEAD. This ensures versions are unique if + multiple release occur on the same date. + """ + args = ["git", "show", "-s", "--format=%ct", "HEAD"] + stdout = subprocess.check_output(args, text=True) + timestamp = float(stdout.strip()) + date = datetime.datetime.fromtimestamp(timestamp, datetime.timezone.utc) + + commits = count_commits_on_date(date) - 1 # Exclude HEAD. + + # Don't use strftime because it includes leading zeros, which are against PEP 440. + return f"{date.year}.{date.month}.{date.day}.{commits}" + + +def count_commits_on_date(dt: datetime.datetime) -> int: + """Return the amount of commits made on the given UTC aware datetime.""" + dt = dt.combine(dt - datetime.timedelta(days=1), dt.max.time(), dt.tzinfo) + + # git log uses the committer date for this, not the author date. + args = ["git", "log", "--oneline", "--after", str(dt.timestamp())] + stdout = subprocess.check_output(args, text=True) + + return stdout.strip().count("\n") -- cgit v1.2.3 From 8d33cab2cb3baf179941e9692b682150d50bbbe5 Mon Sep 17 00:00:00 2001 From: MarkKoz <1515135+MarkKoz@users.noreply.github.com> Date: Tue, 31 May 2022 14:06:54 -0700 Subject: Docker: install package in image and use version to tag it --- .dockerignore | 8 ++++++-- .github/workflows/build.yaml | 24 ++++++++++++------------ .github/workflows/deploy.yaml | 7 +++---- .github/workflows/main.yaml | 4 ++-- .github/workflows/test.yaml | 6 +++--- Dockerfile | 19 ++++++++++--------- docker-compose.yml | 3 ++- scripts/version.py | 4 ++++ snekbox/__init__.py | 2 +- snekbox/utils/logging.py | 5 ++--- 10 files changed, 45 insertions(+), 37 deletions(-) (limited to 'scripts/version.py') diff --git a/.dockerignore b/.dockerignore index b2a96dd..6a360ff 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,9 +2,13 @@ * # Make exceptions for what's needed -!snekbox +!.git/ !config/ !requirements/ -!tests +!scripts/ +!snekbox/ +!tests/ !LICENSE +!NOTICE !pyproject.toml +!README.md diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 28e5b69..e5791c9 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -4,9 +4,9 @@ on: artifact: description: The name of the uploaded image aretfact. value: ${{ jobs.build.outputs.artifact }} - tag: - description: The tag used for the built image. - value: ${{ jobs.build.outputs.tag }} + version: + description: The package's version. + value: ${{ jobs.build.outputs.version }} jobs: build: @@ -14,21 +14,21 @@ jobs: runs-on: ubuntu-latest outputs: artifact: ${{ env.artifact }} - tag: ${{ steps.sha_tag.outputs.tag }} + version: ${{ steps.version.outputs.version }} env: artifact: image_artifact_snekbox-venv steps: - # Create a short SHA with which to tag built images. - - name: Create SHA Container Tag - id: sha_tag - run: | - tag=$(cut -c 1-7 <<< $GITHUB_SHA) - echo "::set-output name=tag::$tag" - - name: Checkout code uses: actions/checkout@v2 + - name: Get version + id: version + run: | + set -eu + version=$(python scripts/version.py) + echo "::set-output name=version::version" + # The current version (v2) of Docker's build-push action uses buildx, # which comes with BuildKit. It has cache features which can speed up # the builds. See https://github.com/docker/build-push-action @@ -83,7 +83,7 @@ jobs: ghcr.io/python-discord/snekbox-base:latest ghcr.io/python-discord/snekbox-venv:latest cache-to: ${{ steps.cache_config.outputs.cache_to }} - tags: ghcr.io/python-discord/snekbox-venv:${{ steps.sha_tag.outputs.tag }} + tags: ghcr.io/python-discord/snekbox-venv:${{ steps.version.outputs.version }} # Make the image available as an artifact so other jobs will be able to # download it. diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 3b12921..977c317 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -4,7 +4,7 @@ on: artifact: required: true type: string - tag: + version: required: true type: string secrets: @@ -55,8 +55,7 @@ jobs: cache-to: type=inline tags: | ghcr.io/python-discord/snekbox:latest - ghcr.io/python-discord/snekbox:${{ inputs.tag }} - build-args: git_sha=${{ github.sha }} + ghcr.io/python-discord/snekbox:${{ inputs.version }} # Deploy to Kubernetes. - name: Authenticate with Kubernetes @@ -69,7 +68,7 @@ jobs: uses: Azure/k8s-deploy@v1 with: manifests: deployment.yaml - images: 'ghcr.io/python-discord/snekbox:${{ inputs.tag }}' + images: 'ghcr.io/python-discord/snekbox:${{ inputs.version }}' kubectl-version: 'latest' # Push the base image to GHCR, with an inline cache manifest. diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index f28ab61..b581ba3 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -16,13 +16,13 @@ jobs: needs: build with: artifact: ${{ needs.build.outputs.artifact }} - tag: ${{ needs.build.outputs.tag }} + version: ${{ needs.build.outputs.version }} deploy: uses: ./.github/workflows/deploy.yaml if: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/main' }} needs: [build, lint, test] with: artifact: ${{ needs.build.outputs.artifact }} - tag: ${{ needs.build.outputs.tag }} + version: ${{ needs.build.outputs.version }} secrets: KUBECONFIG: ${{ secrets.KUBECONFIG }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index f7f3635..a9fcade 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -4,7 +4,7 @@ on: artifact: required: true type: string - tag: + version: required: true type: string @@ -38,7 +38,7 @@ jobs: - name: Run tests id: run_tests run: | - export IMAGE_SUFFIX='-venv:${{ inputs.tag }}' + export IMAGE_SUFFIX='-venv:${{ inputs.version }}' docker-compose run \ --rm -T -e COVERAGE_DATAFILE=.coverage.${{ matrix.os }} \ snekbox \ @@ -57,7 +57,7 @@ jobs: - name: Docker cleanup if: matrix.os == 'self-hosted' && always() run: | - export IMAGE_SUFFIX='-venv:${{ inputs.tag }}' + export IMAGE_SUFFIX='-venv:${{ inputs.version }}' docker-compose down --rmi all --remove-orphans -v -t 0 report: diff --git a/Dockerfile b/Dockerfile index 2382b8b..ef696e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,4 @@ +# syntax=docker/dockerfile:1 FROM python:3.10-slim-buster as builder WORKDIR /nsjail @@ -31,6 +32,7 @@ ENV PATH=/root/.local/bin:$PATH \ RUN apt-get -y update \ && apt-get install -y \ gcc=4:8.3.* \ + git=1:2.20.* \ libnl-route-3-200=3.4.* \ libprotobuf17=3.6.* \ && rm -rf /var/lib/apt/lists/* @@ -60,18 +62,17 @@ RUN if [ -n "${DEV}" ]; \ fi # At the end to avoid re-installing dependencies when only a config changes. -# It's in the venv image because the final image is not used during development. COPY config/ /snekbox/config/ -# ------------------------------------------------------------------------------ -FROM venv - ENTRYPOINT ["gunicorn"] CMD ["-c", "config/gunicorn.conf.py"] -COPY . /snekbox -WORKDIR /snekbox +# ------------------------------------------------------------------------------ +FROM venv -# At the end to prevent it from invalidating the layer cache. -ARG git_sha="development" -ENV GIT_SHA=$git_sha +# Use a separate directory to avoid importing the source over the instaled pkg. +# The venv already installed dependencies, so nothing besides snekbox itself +# will be installed. Note requirements.pip cannot be used as a constraint file +# because it contains extras, which pip disallows. +RUN --mount=source=.,target=/snekbox_src,rw \ + pip install /snekbox_src[gunicorn,sentry] \ diff --git a/docker-compose.yml b/docker-compose.yml index 3854825..aa1a0f5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ services: container_name: snekbox_dev hostname: snekbox_dev privileged: true - image: ghcr.io/python-discord/snekbox${IMAGE_SUFFIX:-:dev} + image: ghcr.io/python-discord/snekbox${IMAGE_SUFFIX:--venv:dev} ports: - 8060:8060 init: true @@ -17,6 +17,7 @@ services: build: context: . dockerfile: Dockerfile + target: venv args: DEV: 1 cache_from: diff --git a/scripts/version.py b/scripts/version.py index 9076b93..bf8d509 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -32,3 +32,7 @@ def count_commits_on_date(dt: datetime.datetime) -> int: stdout = subprocess.check_output(args, text=True) return stdout.strip().count("\n") + + +if __name__ == "__main__": + print(get_version()) diff --git a/snekbox/__init__.py b/snekbox/__init__.py index a3a5f09..657c032 100644 --- a/snekbox/__init__.py +++ b/snekbox/__init__.py @@ -14,5 +14,5 @@ from snekbox.utils.logging import init_logger, init_sentry # noqa: E402 __all__ = ("NsJail", "SnekAPI") -init_sentry() +init_sentry(__version__) init_logger(DEBUG) diff --git a/snekbox/utils/logging.py b/snekbox/utils/logging.py index 9a713f8..c15e3f1 100644 --- a/snekbox/utils/logging.py +++ b/snekbox/utils/logging.py @@ -19,7 +19,7 @@ def init_logger(debug: bool) -> None: log.addHandler(handler) -def init_sentry() -> None: +def init_sentry(version: str) -> None: """Initialise the Sentry SDK if it's installed.""" try: import sentry_sdk @@ -27,10 +27,9 @@ def init_sentry() -> None: except ImportError: return - git_sha = os.environ.get("GIT_SHA", "development") sentry_sdk.init( dsn=os.environ.get("SNEKBOX_SENTRY_DSN", ""), integrations=[FalconIntegration()], send_default_pii=True, - release=f"snekbox@{git_sha}" + release=f"snekbox@{version}" ) -- cgit v1.2.3