From 3f21f98af69f68fca09d3d592ac6606869fa913a Mon Sep 17 00:00:00 2001 From: s3lph <1375407-s3lph@users.noreply.gitlab.com> Date: Fri, 14 Oct 2022 02:02:08 +0200 Subject: [PATCH] Changelog and release management --- .gitignore | 1 + .gitlab-ci.yml | 19 ++++++- Makefile | 19 +++++++ package/release.py | 134 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 Makefile create mode 100755 package/release.py diff --git a/.gitignore b/.gitignore index b953c86..bb30560 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ prometheus-dnssec-exporter config.yaml +.changes diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e178521..1aa9590 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,18 +2,35 @@ image: golang:1.18 before_script: + - export PDE_FULL_VERSION=$(git describe --tags --dirty | sed -re s/^v//) + - export PDE_VERSION=$(echo $PDE_FULL_VERSION | cut -d- -f1) + - export PDE_REVISION=$(echo $PDE_FULL_VERSION | cut -d- -f2-) - go get -v stages: - test + - build + - release compile: stage: test script: - - go build + - make prometheus-dnssec-exporter + artifacts: + paths: + - prometheus-dnssec-exporter golangci-lint: stage: test script: - go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.45.2 - golangci-lint run + +release: + image: debian:bullseye + stage: deploy + script: + - make .changes + - python package/release.py + only: + - tags diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e51ef0a --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ + +PDE_VERSION=$$(git describe --tags --dirty | sed -re s/^v// | cut -d- -f1) +PDE_REVISION=$$(git describe --tags --dirty | cut -d- -f2-) + +LD_VERSION=-X github.com/prometheus/common/version.Version=$(PDE_VERSION) +LD_REVISION=-X github.com/prometheus/common/version.Revision=$(PDE_REVISION) +LD_BRANCH=-X github.com/prometheus/common/version.Branch=$$(git branch | grep '*' | cut -d ' ' -f 2-) +LD_USER=-X github.com/prometheus/common/version.BuildUser=$$(whoami)@$$(hostname -f) +LD_DATE=-X github.com/prometheus/common/version.BuildDate=$$(date --iso-8601=seconds) +LDFLAGS=-s $(LD_VERSION) $(LD_REVISION) $(LD_BRANCH) $(LD_USER) $(LD_DATE) + +prometheus-dnssec-exporter: + go build -tags netgo -ldflags="$(LDFLAGS)" -o prometheus-dnssec-exporter + +.changes: + git log --format='- %s' $$(git describe --tags --abbrev=0 @^)..@ > .changes + +clean: + rm -f prometheus-dnssec-exporter .changes diff --git a/package/release.py b/package/release.py new file mode 100755 index 0000000..2454fcd --- /dev/null +++ b/package/release.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 + +from typing import Any, Dict, List, Optional, Tuple + +import os +import sys +import json +import urllib.request +import http.client +from urllib.error import HTTPError + + +def read_changelog(tag: str) -> Optional[str]: + with open('.changes', 'r') as f: + return f.read() + + +def fetch_job_ids(project_id: int, pipeline_id: int, api_token: str) -> Dict[str, str]: + url: str = f'https://gitlab.com/api/v4/projects/{project_id}/pipelines/{pipeline_id}/jobs' + headers: Dict[str, str] = { + 'Private-Token': api_token, + 'User-Agent': 'curl/7.70.0' + } + req = urllib.request.Request(url, headers=headers) + try: + resp: http.client.HTTPResponse = urllib.request.urlopen(req) + except HTTPError as e: + print(e.read().decode()) + sys.exit(1) + resp_data: bytes = resp.read() + joblist: List[Dict[str, Any]] = json.loads(resp_data.decode()) + + jobidmap: Dict[str, str] = {} + for job in joblist: + name: str = job['name'] + job_id: str = job['id'] + jobidmap[name] = job_id + return jobidmap + + +def fetch_binary_url(base_url: str, job_ids: Dict[str, str]) -> Optional[Tuple[str, str]]: + mybase: str = f'{base_url}/jobs/{job_ids["compile"]}/artifacts/raw' + binary_url: str = f'{mybase}/{wheel_filename}' + return binary_url + + +def main(): + api_token: Optional[str] = os.getenv('GITLAB_API_TOKEN') + release_tag: Optional[str] = os.getenv('CI_COMMIT_TAG') + project_name: Optional[str] = os.getenv('CI_PROJECT_PATH') + project_id: Optional[str] = os.getenv('CI_PROJECT_ID') + pipeline_id: Optional[str] = os.getenv('CI_PIPELINE_ID') + if api_token is None: + print('GITLAB_API_TOKEN is not set.', file=sys.stderr) + sys.exit(1) + if release_tag is None: + print('CI_COMMIT_TAG is not set.', file=sys.stderr) + sys.exit(1) + if project_name is None: + print('CI_PROJECT_PATH is not set.', file=sys.stderr) + sys.exit(1) + if project_id is None: + print('CI_PROJECT_ID is not set.', file=sys.stderr) + sys.exit(1) + if pipeline_id is None: + print('CI_PIPELINE_ID is not set.', file=sys.stderr) + sys.exit(1) + + changelog: Optional[str] = read_changelog(release_tag) + if changelog is None: + print('Changelog could not be parsed.', file=sys.stderr) + sys.exit(1) + + job_ids: Dict[str, str] = fetch_job_ids(project_id, pipeline_id, api_token) + + base_url: str = f'https://gitlab.com/{project_name}/-' + + binary_url = fetch_wheel_url(base_url, job_ids) + + augmented_changelog = f'''{changelog.strip()} + +### Download + +- [prometheus-dnssec-exporter]({binary_url}) + +''' + + post_body: str = json.dumps({ + 'tag_name': release_tag, + 'description': augmented_changelog, + 'assets': { + 'links': [ + { + 'name': 'promtheus-dnssec-exporter', + 'url': binary_url, + 'link_type': 'package' + } + ] + } + }) + + gitlab_release_api_url: str = \ + f'https://gitlab.com/api/v4/projects/{project_id}/releases' + headers: Dict[str, str] = { + 'Private-Token': api_token, + 'Content-Type': 'application/json; charset=utf-8', + 'User-Agent': 'curl/7.70.0' + } + + request = urllib.request.Request( + gitlab_release_api_url, + post_body.encode('utf-8'), + headers=headers, + method='POST' + ) + try: + response: http.client.HTTPResponse = urllib.request.urlopen(request) + except HTTPError as e: + print(e.read().decode()) + sys.exit(1) + response_bytes: bytes = response.read() + response_str: str = response_bytes.decode() + response_data: Dict[str, Any] = json.loads(response_str) + + if response_data['tag_name'] != release_tag: + print('Something went wrong...', file=sys.stderr) + print(response_str, file=sys.stderr) + sys.exit(1) + + print(response_data['description']) + + +if __name__ == '__main__': + main()