mirror of
https://github.com/pyTooling/Actions.git
synced 2026-02-12 19:16:57 +08:00
194 lines
8.6 KiB
Python
Executable File
194 lines
8.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# ==================================================================================================================== #
|
|
# Authors: #
|
|
# Patrick Lehmann #
|
|
# Unai Martinez-Corral #
|
|
# #
|
|
# ==================================================================================================================== #
|
|
# Copyright 2020-2022 The pyTooling 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. #
|
|
# #
|
|
# SPDX-License-Identifier: Apache-2.0 #
|
|
# ==================================================================================================================== #
|
|
import re
|
|
from sys import argv as sys_argv, stdout, exit as sys_exit
|
|
from os import environ, getenv
|
|
from glob import glob
|
|
from pathlib import Path
|
|
from github import Github, GithubException
|
|
from subprocess import check_call
|
|
|
|
|
|
paramTag = getenv("INPUT_TAG", "tip")
|
|
paramFiles = getenv("INPUT_FILES", None).split()
|
|
paramRM = getenv("INPUT_RM", "false") == "true"
|
|
paramSnapshots = getenv("INPUT_SNAPSHOTS", "true").lower() == "true"
|
|
paramToken = (
|
|
environ["GITHUB_TOKEN"]
|
|
if "GITHUB_TOKEN" in environ
|
|
else environ["INPUT_TOKEN"]
|
|
if "INPUT_TOKEN" in environ
|
|
else None
|
|
)
|
|
paramRepo = getenv("GITHUB_REPOSITORY", None)
|
|
paramRef = getenv("GITHUB_REF", None)
|
|
paramSHA = getenv("GITHUB_SHA", None)
|
|
|
|
|
|
def GetListOfArtifacts(argv, files):
|
|
print("· Get list of artifacts to be uploaded")
|
|
args = files if files is not None else []
|
|
if len(argv) > 1:
|
|
args += argv[1:]
|
|
if len(args) == 1 and args[0].lower() == "none":
|
|
print("! Skipping 'files' because it's set to 'none'.")
|
|
return []
|
|
elif len(args) == 0:
|
|
stdout.flush()
|
|
raise (Exception("Glob patterns need to be provided as positional arguments or through envvar 'INPUT_FILES'!"))
|
|
else:
|
|
flist = []
|
|
for item in args:
|
|
print(f" glob({item!s}):")
|
|
for fname in [fname for fname in glob(item, recursive=True) if not Path(fname).is_dir()]:
|
|
if Path(fname).stat().st_size == 0:
|
|
print(f" - ! Skipping empty file {fname!s}.")
|
|
continue
|
|
print(f" - {fname!s}")
|
|
flist.append(fname)
|
|
if len(flist) < 1:
|
|
stdout.flush()
|
|
raise (Exception("Empty list of files to upload/update!"))
|
|
return sorted(flist)
|
|
|
|
|
|
def GetGitHubAPIHandler(token):
|
|
print("· Get GitHub API handler (authenticate)")
|
|
if token is not None:
|
|
return Github(token)
|
|
raise (Exception("Need credentials to authenticate! Please, provide 'GITHUB_TOKEN' or 'INPUT_TOKEN'"))
|
|
|
|
|
|
def CheckRefSemVer(gh_ref, tag, snapshots):
|
|
print("· Check SemVer compliance of the reference/tag")
|
|
env_tag = None
|
|
if gh_ref[0:10] == "refs/tags/":
|
|
env_tag = gh_ref[10:]
|
|
if env_tag != tag:
|
|
rexp = r"^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"
|
|
semver = re.search(rexp, env_tag)
|
|
if semver == None and env_tag[0] == "v":
|
|
semver = re.search(rexp, env_tag[1:])
|
|
tag = env_tag
|
|
if semver == None:
|
|
print(f"! Could not get semver from {gh_ref!s}")
|
|
print(f"! Treat tag '{tag!s}' as a release")
|
|
return (tag, env_tag, False)
|
|
else:
|
|
if semver.group("prerelease") is None:
|
|
# is a regular semver compilant tag
|
|
return (tag, env_tag, False)
|
|
elif snapshots:
|
|
# is semver compilant prerelease tag, thus a snapshot (we skip it)
|
|
print("! Skipping snapshot prerelease.")
|
|
sys_exit()
|
|
|
|
return (tag, env_tag, True)
|
|
|
|
|
|
def GetRepositoryHandler(gh, repo):
|
|
print("· Get Repository handler")
|
|
if repo is None:
|
|
stdout.flush()
|
|
raise (Exception("Repository name not defined! Please set 'GITHUB_REPOSITORY"))
|
|
return gh.get_repo(repo)
|
|
|
|
|
|
def GetOrCreateRelease(gh_repo, tag, sha, is_prerelease):
|
|
print("· Get Release handler")
|
|
gh_tag = None
|
|
try:
|
|
gh_tag = gh_repo.get_git_ref(f"tags/{tag!s}")
|
|
except Exception:
|
|
stdout.flush()
|
|
|
|
if gh_tag:
|
|
try:
|
|
return (gh_repo.get_release(tag), False)
|
|
except Exception:
|
|
return (gh_repo.create_git_release(tag, tag, "", draft=True, prerelease=is_prerelease), True)
|
|
else:
|
|
err_msg = f"Tag/release '{tag!s}' does not exist and could not create it!"
|
|
if sha is None:
|
|
raise (Exception(err_msg))
|
|
try:
|
|
return (
|
|
gh_repo.create_git_tag_and_release(
|
|
tag, "", tag, "", sha, "commit", draft=True, prerelease=is_prerelease
|
|
),
|
|
True,
|
|
)
|
|
except Exception:
|
|
raise (Exception(err_msg))
|
|
|
|
|
|
def UpdateReference(gh_release, tag, sha, is_prerelease, is_draft):
|
|
print("· Update Release reference (force-push tag)")
|
|
|
|
if is_draft:
|
|
# Unfortunately, it seems not possible to update fields 'created_at' or 'published_at'.
|
|
print(" > Update (pre-)release")
|
|
gh_release.update_release(
|
|
gh_release.title,
|
|
"" if gh_release.body is None else gh_release.body,
|
|
draft=False,
|
|
prerelease=is_prerelease,
|
|
tag_name=gh_release.tag_name,
|
|
target_commitish=gh_release.target_commitish,
|
|
)
|
|
|
|
if sha is not None:
|
|
print(f" > Force-push '{tag!s}' to {sha!s}")
|
|
gh_repo.get_git_ref(f"tags/{tag!s}").edit(sha)
|
|
|
|
|
|
files = GetListOfArtifacts(sys_argv, paramFiles)
|
|
stdout.flush()
|
|
[tag, env_tag, is_prerelease] = CheckRefSemVer(paramRef, paramTag, paramSnapshots)
|
|
stdout.flush()
|
|
gh_repo = GetRepositoryHandler(GetGitHubAPIHandler(paramToken), paramRepo)
|
|
stdout.flush()
|
|
[gh_release, is_draft] = GetOrCreateRelease(gh_repo, tag, paramSHA, is_prerelease)
|
|
stdout.flush()
|
|
|
|
if paramRM:
|
|
print("· RM set. All previous assets are being cleared...")
|
|
for asset in gh_release.get_assets():
|
|
print(f" - {asset.name}")
|
|
asset.delete_asset()
|
|
stdout.flush()
|
|
|
|
if len(files) > 0:
|
|
print("· Upload assets")
|
|
env = environ.copy()
|
|
env["GITHUB_TOKEN"] = paramToken
|
|
cmd = ["gh", "release", "upload", "--repo", paramRepo, "--clobber", tag] + files
|
|
print(f" > {' '.join(cmd)}")
|
|
check_call(cmd, env=env)
|
|
stdout.flush()
|
|
else:
|
|
print("! Skipping uploading assets because the file list is empty.")
|
|
|
|
UpdateReference(gh_release, tag, paramSHA if env_tag is None else None, is_prerelease, is_draft)
|