Compare commits
3
Commits
2a24276b78
...
v0.1.15
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a0768bb8c | ||
|
|
29120ba9fa | ||
|
|
2a56300d81 |
@@ -14,6 +14,8 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
publish-packages:
|
publish-packages:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
GITEA_REPOSITORY: ${{ gitea.repository }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
||||||
with:
|
with:
|
||||||
@@ -29,7 +31,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
REQUESTED_TAG: ${{ inputs.release_tag }}
|
REQUESTED_TAG: ${{ inputs.release_tag }}
|
||||||
TRIGGER_TAG: ${{ gitea.ref_name }}
|
TRIGGER_TAG: ${{ gitea.ref_name }}
|
||||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
tag="${REQUESTED_TAG:-$TRIGGER_TAG}"
|
tag="${REQUESTED_TAG:-$TRIGGER_TAG}"
|
||||||
@@ -43,24 +44,6 @@ jobs:
|
|||||||
echo "Release tag is not contained in main" >&2
|
echo "Release tag is not contained in main" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
python - "$tag" <<'PY'
|
|
||||||
import fnmatch
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import urllib.request
|
|
||||||
|
|
||||||
tag = sys.argv[1]
|
|
||||||
repository = os.environ["GITEA_REPOSITORY"]
|
|
||||||
request = urllib.request.Request(
|
|
||||||
f"{os.environ['GITEA_API_URL']}/repos/{repository}/tag_protections",
|
|
||||||
headers={"Authorization": f"token {os.environ['GITEA_TOKEN']}"},
|
|
||||||
)
|
|
||||||
with urllib.request.urlopen(request, timeout=30) as response:
|
|
||||||
protections = json.load(response)
|
|
||||||
if not any(fnmatch.fnmatchcase(tag, item.get("name_pattern", "")) for item in protections):
|
|
||||||
raise SystemExit(f"Release tag {tag!r} is not covered by repository tag protection")
|
|
||||||
PY
|
|
||||||
git checkout --detach "$tag"
|
git checkout --detach "$tag"
|
||||||
printf 'RELEASE_TAG=%s\n' "$tag" >> "$GITEA_ENV"
|
printf 'RELEASE_TAG=%s\n' "$tag" >> "$GITEA_ENV"
|
||||||
printf 'SOURCE_DATE_EPOCH=%s\n' "$(git show -s --format=%ct HEAD)" >> "$GITEA_ENV"
|
printf 'SOURCE_DATE_EPOCH=%s\n' "$(git show -s --format=%ct HEAD)" >> "$GITEA_ENV"
|
||||||
@@ -130,7 +113,7 @@ jobs:
|
|||||||
const escapedRepository = repository.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
const escapedRepository = repository.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||||
const gitTag = specifier.match(
|
const gitTag = specifier.match(
|
||||||
new RegExp(
|
new RegExp(
|
||||||
`^git\\+(?:ssh://git@|https://)git\\.add-ideas\\.de/GovOPlaN/${escapedRepository}\\.git#v([0-9]+\\.[0-9]+\\.[0-9]+)$`,
|
`^git\\+(?:ssh://git@|https://)git\\.add-ideas\\.de/(?:GovOPlaN|add-ideas)/${escapedRepository}\\.git#v([0-9]+\\.[0-9]+\\.[0-9]+)$`,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (gitTag) {
|
if (gitTag) {
|
||||||
@@ -180,6 +163,78 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: module-packages-${{ gitea.ref_name }}
|
name: module-packages-${{ gitea.ref_name }}
|
||||||
path: dist/package-artifacts.json
|
path: dist/package-artifacts.json
|
||||||
|
- name: Check immutable registry state
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
PACKAGE_TOKEN: ${{ secrets.GOVOPLAN_PACKAGE_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
test -n "$PACKAGE_TOKEN"
|
||||||
|
python - <<'PY'
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import tomllib
|
||||||
|
from urllib.error import HTTPError
|
||||||
|
from urllib.parse import quote
|
||||||
|
from urllib.request import Request, urlopen
|
||||||
|
|
||||||
|
api_root = "https://git.add-ideas.de/api/v1/packages/GovOPlaN"
|
||||||
|
token = os.environ["PACKAGE_TOKEN"]
|
||||||
|
|
||||||
|
def should_publish(kind, name, version, path):
|
||||||
|
package_url = "/".join(
|
||||||
|
(api_root, kind, quote(name, safe=""), quote(version, safe=""), "files")
|
||||||
|
)
|
||||||
|
request = Request(
|
||||||
|
package_url,
|
||||||
|
headers={"Accept": "application/json", "Authorization": f"token {token}"},
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
with urlopen(request, timeout=30) as response:
|
||||||
|
files = json.load(response)
|
||||||
|
except HTTPError as exc:
|
||||||
|
if exc.code == 404:
|
||||||
|
print(f"{kind} package {name}=={version} is not published yet")
|
||||||
|
return True
|
||||||
|
raise
|
||||||
|
if not isinstance(files, list) or len(files) != 1:
|
||||||
|
raise SystemExit(
|
||||||
|
f"immutable {kind} package {name}=={version} has an unexpected file set"
|
||||||
|
)
|
||||||
|
expected_sha256 = hashlib.sha256(path.read_bytes()).hexdigest()
|
||||||
|
if files[0].get("sha256") != expected_sha256:
|
||||||
|
raise SystemExit(
|
||||||
|
f"immutable {kind} package {name}=={version} already exists with a different SHA-256"
|
||||||
|
)
|
||||||
|
print(f"verified existing {kind} package {name}=={version} ({expected_sha256})")
|
||||||
|
return False
|
||||||
|
|
||||||
|
project = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))["project"]
|
||||||
|
wheels = tuple(Path("dist").glob("*.whl"))
|
||||||
|
if len(wheels) != 1:
|
||||||
|
raise SystemExit("release build must contain exactly one wheel")
|
||||||
|
publish_pypi = should_publish(
|
||||||
|
"pypi", str(project["name"]), str(project["version"]), wheels[0]
|
||||||
|
)
|
||||||
|
|
||||||
|
tarballs = tuple(Path("dist").glob("*.tgz"))
|
||||||
|
if len(tarballs) > 1:
|
||||||
|
raise SystemExit("release build must contain at most one npm package")
|
||||||
|
publish_npm = False
|
||||||
|
if tarballs:
|
||||||
|
webui = json.loads(
|
||||||
|
Path(".package-webui/package.json").read_text(encoding="utf-8")
|
||||||
|
)
|
||||||
|
publish_npm = should_publish(
|
||||||
|
"npm", str(webui["name"]), str(webui["version"]), tarballs[0]
|
||||||
|
)
|
||||||
|
|
||||||
|
with Path(os.environ["GITEA_ENV"]).open("a", encoding="utf-8") as env_file:
|
||||||
|
env_file.write(f"PUBLISH_PYPI={int(publish_pypi)}\n")
|
||||||
|
env_file.write(f"PUBLISH_NPM={int(publish_npm)}\n")
|
||||||
|
PY
|
||||||
- name: Publish wheel and WebUI package
|
- name: Publish wheel and WebUI package
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
@@ -189,13 +244,17 @@ jobs:
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
test -n "$PACKAGE_USERNAME"
|
test -n "$PACKAGE_USERNAME"
|
||||||
test -n "$PACKAGE_TOKEN"
|
test -n "$PACKAGE_TOKEN"
|
||||||
TWINE_USERNAME="$PACKAGE_USERNAME" TWINE_PASSWORD="$PACKAGE_TOKEN" \
|
if [[ "$PUBLISH_PYPI" == 1 ]]; then
|
||||||
python -m twine upload --non-interactive \
|
TWINE_USERNAME="$PACKAGE_USERNAME" TWINE_PASSWORD="$PACKAGE_TOKEN" \
|
||||||
--repository-url https://git.add-ideas.de/api/packages/GovOPlaN/pypi \
|
python -m twine upload --non-interactive \
|
||||||
dist/*.whl
|
--repository-url https://git.add-ideas.de/api/packages/GovOPlaN/pypi \
|
||||||
|
dist/*.whl
|
||||||
|
else
|
||||||
|
echo "Exact wheel is already present; skipping immutable retry."
|
||||||
|
fi
|
||||||
shopt -s nullglob
|
shopt -s nullglob
|
||||||
webui_packages=(dist/*.tgz)
|
webui_packages=(dist/*.tgz)
|
||||||
if (( ${#webui_packages[@]} )); then
|
if (( ${#webui_packages[@]} )) && [[ "$PUBLISH_NPM" == 1 ]]; then
|
||||||
npmrc="$(mktemp)"
|
npmrc="$(mktemp)"
|
||||||
trap 'rm -f "$npmrc"' EXIT
|
trap 'rm -f "$npmrc"' EXIT
|
||||||
chmod 600 "$npmrc"
|
chmod 600 "$npmrc"
|
||||||
@@ -203,7 +262,9 @@ jobs:
|
|||||||
'@govoplan:registry=https://git.add-ideas.de/api/packages/GovOPlaN/npm/' \
|
'@govoplan:registry=https://git.add-ideas.de/api/packages/GovOPlaN/npm/' \
|
||||||
"//git.add-ideas.de/api/packages/GovOPlaN/npm/:_authToken=$PACKAGE_TOKEN" \
|
"//git.add-ideas.de/api/packages/GovOPlaN/npm/:_authToken=$PACKAGE_TOKEN" \
|
||||||
> "$npmrc"
|
> "$npmrc"
|
||||||
NPM_CONFIG_USERCONFIG="$npmrc" npm publish "${webui_packages[0]}" \
|
NPM_CONFIG_USERCONFIG="$npmrc" npm publish "./${webui_packages[0]}" \
|
||||||
--ignore-scripts --access public \
|
--ignore-scripts --access public \
|
||||||
--registry https://git.add-ideas.de/api/packages/GovOPlaN/npm/
|
--registry https://git.add-ideas.de/api/packages/GovOPlaN/npm/
|
||||||
|
elif (( ${#webui_packages[@]} )); then
|
||||||
|
echo "Exact WebUI package is already present; skipping immutable retry."
|
||||||
fi
|
fi
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@govoplan/wiki",
|
"name": "@govoplan/wiki",
|
||||||
"version": "0.1.14",
|
"version": "0.1.15",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "GovOPlaN collaborative Wiki module.",
|
"description": "GovOPlaN collaborative Wiki module.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
+3
-3
@@ -4,15 +4,15 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "govoplan-wiki"
|
name = "govoplan-wiki"
|
||||||
version = "0.1.14"
|
version = "0.1.15"
|
||||||
description = "GovOPlaN collaborative Wiki module."
|
description = "GovOPlaN collaborative Wiki module."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
license = { file = "LICENSE" }
|
license = { file = "LICENSE" }
|
||||||
authors = [{ name = "GovOPlaN" }]
|
authors = [{ name = "GovOPlaN" }]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"govoplan-core>=0.1.14",
|
"govoplan-core>=0.1.15",
|
||||||
"govoplan-access>=0.1.8",
|
"govoplan-access>=0.1.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.setuptools.packages.find]
|
[tool.setuptools.packages.find]
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from govoplan_core.core.provider_governance import declared_module_architecture
|
|||||||
|
|
||||||
MODULE_ID = "wiki"
|
MODULE_ID = "wiki"
|
||||||
MODULE_NAME = "Wiki"
|
MODULE_NAME = "Wiki"
|
||||||
MODULE_VERSION = "0.1.14"
|
MODULE_VERSION = "0.1.15"
|
||||||
READ_SCOPE = "wiki:page:read"
|
READ_SCOPE = "wiki:page:read"
|
||||||
WRITE_SCOPE = "wiki:page:write"
|
WRITE_SCOPE = "wiki:page:write"
|
||||||
ADMIN_SCOPE = "wiki:space:admin"
|
ADMIN_SCOPE = "wiki:space:admin"
|
||||||
|
|||||||
Reference in New Issue
Block a user