mirror of
https://github.com/dexoron/dcr.git
synced 2026-10-21 12:38:30 +00:00
feat: add automated repository mirroring workflows and update docs
- Add GitHub Actions workflows for code and release mirroring - Remove manual sync-releases-to-gitlab.py script - Update .gitignore to track .github/ directory - Document repository mirrors and VS Code extension recommendations
This commit is contained in:
37
.github/workflows/code-mirror.yml
vendored
Normal file
37
.github/workflows/code-mirror.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: Mirror source code to GitVerse
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: code-mirror-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
mirror:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Mirror all branches
|
||||
env:
|
||||
GITVERSE_PAT: ${{ secrets.GITVERSE_PAT }}
|
||||
GITVERSE_ORG: ${{ vars.GITVERSE_ORG || 'dcr_labs' }}
|
||||
GITVERSE_REPO: ${{ vars.GITVERSE_REPO || 'dcr' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
test -n "$GITVERSE_PAT" || { echo 'GITVERSE_PAT is not configured' >&2; exit 1; }
|
||||
remote="https://oauth2:${GITVERSE_PAT}@gitverse.ru/${GITVERSE_ORG}/${GITVERSE_REPO}.git"
|
||||
git remote add gitverse "$remote"
|
||||
# Populate local refs first, so a manual run mirrors every branch too.
|
||||
git fetch origin '+refs/heads/*:refs/heads/*'
|
||||
git push --prune --force gitverse 'refs/heads/*:refs/heads/*'
|
||||
186
.github/workflows/release-mirror.yml
vendored
Normal file
186
.github/workflows/release-mirror.yml
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
name: Mirror releases to GitVerse, SourceCraft, and GitLab
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- Release
|
||||
types:
|
||||
- completed
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: Git tag of the GitHub release to mirror (for example v0.7.1)
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
mirror:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Resolve release tag
|
||||
id: release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
MANUAL_TAG: ${{ inputs.tag }}
|
||||
WORKFLOW_HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
||||
WORKFLOW_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tag="$MANUAL_TAG"
|
||||
if [ -z "$tag" ] && [[ "$WORKFLOW_HEAD_BRANCH" == v* ]]; then
|
||||
tag="$WORKFLOW_HEAD_BRANCH"
|
||||
fi
|
||||
if [ -z "$tag" ] && [ -n "$WORKFLOW_HEAD_SHA" ]; then
|
||||
releases=$(curl -fsSL -H "Authorization: Bearer $GH_TOKEN" \
|
||||
-H 'Accept: application/vnd.github+json' \
|
||||
"https://api.github.com/repos/${GITHUB_REPOSITORY}/releases?per_page=100")
|
||||
while IFS= read -r candidate; do
|
||||
ref=$(curl -fsSL -H "Authorization: Bearer $GH_TOKEN" \
|
||||
-H 'Accept: application/vnd.github+json' \
|
||||
"https://api.github.com/repos/${GITHUB_REPOSITORY}/git/ref/tags/${candidate}")
|
||||
sha=$(jq -r '.object.sha' <<< "$ref")
|
||||
if [ "$(jq -r '.object.type' <<< "$ref")" = tag ]; then
|
||||
sha=$(curl -fsSL -H "Authorization: Bearer $GH_TOKEN" \
|
||||
-H 'Accept: application/vnd.github+json' \
|
||||
"https://api.github.com/repos/${GITHUB_REPOSITORY}/git/tags/${sha}" | jq -r '.object.sha')
|
||||
fi
|
||||
if [ "$sha" = "$WORKFLOW_HEAD_SHA" ]; then
|
||||
tag="$candidate"
|
||||
break
|
||||
fi
|
||||
done < <(jq -r '.[].tag_name' <<< "$releases")
|
||||
fi
|
||||
if [ -z "$tag" ] || [[ "$tag" != v* ]]; then
|
||||
echo 'No release tag was found; release.yml may have failed before creating a GitHub release.'
|
||||
echo 'found=false' >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
||||
echo 'found=true' >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Download GitHub release metadata and assets
|
||||
if: steps.release.outputs.found == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ steps.release.outputs.tag }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p assets
|
||||
curl -fsSL -H "Authorization: Bearer $GH_TOKEN" \
|
||||
-H 'Accept: application/vnd.github+json' \
|
||||
"https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/tags/${TAG}" > release.json
|
||||
jq -e '.tag_name == $tag' --arg tag "$TAG" release.json >/dev/null
|
||||
jq -r '.assets[] | [.name, .browser_download_url] | @tsv' release.json |
|
||||
while IFS=$'\t' read -r name url; do
|
||||
curl -fsSL -L -H "Authorization: Bearer $GH_TOKEN" \
|
||||
-H 'Accept: application/octet-stream' -o "assets/$name" "$url"
|
||||
done
|
||||
|
||||
- name: Sync tag and release to GitVerse
|
||||
if: steps.release.outputs.found == 'true'
|
||||
env:
|
||||
GITVERSE_PAT: ${{ secrets.GITVERSE_PAT }}
|
||||
GITVERSE_ORG: ${{ vars.GITVERSE_ORG || 'dcr_labs' }}
|
||||
GITVERSE_REPO: ${{ vars.GITVERSE_REPO || 'dcr' }}
|
||||
TAG: ${{ steps.release.outputs.tag }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
test -n "$GITVERSE_PAT" || { echo 'GITVERSE_PAT is not configured' >&2; exit 1; }
|
||||
project="${GITVERSE_ORG}%2F${GITVERSE_REPO}"
|
||||
remote="https://oauth2:${GITVERSE_PAT}@gitverse.ru/${GITVERSE_ORG}/${GITVERSE_REPO}.git"
|
||||
git clone --mirror "https://github.com/${GITHUB_REPOSITORY}.git" mirror.git
|
||||
git -C mirror.git remote add gitverse "$remote"
|
||||
git -C mirror.git push gitverse "refs/tags/${TAG}:refs/tags/${TAG}"
|
||||
|
||||
title=$(jq -r '.name // .tag_name' release.json)
|
||||
notes=$(jq -r '.body // ""' release.json)
|
||||
payload=$(jq -n --arg tag "$TAG" --arg title "$title" --arg notes "$notes" \
|
||||
'{name:$title, tag_name:$tag, description:$notes, ref:$tag}')
|
||||
curl -fsSL -X POST -H "PRIVATE-TOKEN: $GITVERSE_PAT" \
|
||||
-H 'Content-Type: application/json' --data "$payload" \
|
||||
"https://gitverse.ru/api/v4/projects/${project}/releases" || \
|
||||
curl -fsSL -X PUT -H "PRIVATE-TOKEN: $GITVERSE_PAT" \
|
||||
-H 'Content-Type: application/json' --data "$payload" \
|
||||
"https://gitverse.ru/api/v4/projects/${project}/releases/${TAG}"
|
||||
for file in assets/*; do
|
||||
[ -f "$file" ] || continue
|
||||
upload=$(curl -fsSL -X POST -H "PRIVATE-TOKEN: $GITVERSE_PAT" \
|
||||
-F "file=@$file" "https://gitverse.ru/api/v4/projects/${project}/uploads")
|
||||
url=$(jq -r '.url // .file_path' <<< "$upload")
|
||||
name=$(basename "$file")
|
||||
link=$(jq -n --arg name "$name" --arg url "$url" '{name:$name,url:$url}')
|
||||
curl -fsSL -X POST -H "PRIVATE-TOKEN: $GITVERSE_PAT" \
|
||||
-H 'Content-Type: application/json' --data "$link" \
|
||||
"https://gitverse.ru/api/v4/projects/${project}/releases/${TAG}/assets/links" || true
|
||||
done
|
||||
|
||||
- name: Sync tag and release to SourceCraft
|
||||
if: steps.release.outputs.found == 'true'
|
||||
env:
|
||||
SOURCECRAFT_PAT: ${{ secrets.SOURCECRAFT_PAT }}
|
||||
SOURCECRAFT_ORG: ${{ vars.SOURCECRAFT_ORG || 'dexoron-dev' }}
|
||||
SOURCECRAFT_REPO: ${{ vars.SOURCECRAFT_REPO || 'dcr' }}
|
||||
TAG: ${{ steps.release.outputs.tag }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
test -n "$SOURCECRAFT_PAT" || { echo 'SOURCECRAFT_PAT is not configured' >&2; exit 1; }
|
||||
remote="https://anyname:${SOURCECRAFT_PAT}@git.sourcecraft.dev/${SOURCECRAFT_ORG}/${SOURCECRAFT_REPO}.git"
|
||||
git clone "$remote" sourcecraft
|
||||
git -C sourcecraft remote add github "https://github.com/${GITHUB_REPOSITORY}.git"
|
||||
git -C sourcecraft fetch github "refs/tags/${TAG}:refs/tags/${TAG}"
|
||||
git -C sourcecraft push origin "refs/tags/${TAG}"
|
||||
|
||||
title=$(jq -r '.name // .tag_name' release.json)
|
||||
notes=$(jq -r '.body // ""' release.json)
|
||||
payload=$(jq -n --arg tag "$TAG" --arg title "$title" --arg notes "$notes" \
|
||||
'{tag:$tag,title:$title,release_notes:$notes,publish:true}')
|
||||
curl -fsSL -X POST -H "Authorization: Bearer $SOURCECRAFT_PAT" \
|
||||
-H 'Content-Type: application/json' --data "$payload" \
|
||||
"https://api.sourcecraft.tech/repos/${SOURCECRAFT_ORG}/${SOURCECRAFT_REPO}/releases" || \
|
||||
echo 'SourceCraft release already exists; continuing with assets.'
|
||||
for file in assets/*; do
|
||||
[ -f "$file" ] || continue
|
||||
curl -fsSL -X POST -H "Authorization: Bearer $SOURCECRAFT_PAT" \
|
||||
-F "name=$(basename "$file")" -F "file=@$file" \
|
||||
"https://api.sourcecraft.tech/repos/${SOURCECRAFT_ORG}/${SOURCECRAFT_REPO}/releases/tag/${TAG}/attachments" || true
|
||||
done
|
||||
|
||||
- name: Sync release to GitLab
|
||||
if: steps.release.outputs.found == 'true'
|
||||
env:
|
||||
GITLAB_PAT: ${{ secrets.GITLAB_PAT }}
|
||||
GITLAB_PROJECT: ${{ vars.GITLAB_PROJECT || 'dexoron-dev/dcr-tool/dcr' }}
|
||||
TAG: ${{ steps.release.outputs.tag }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
test -n "$GITLAB_PAT" || { echo 'GITLAB_PAT is not configured' >&2; exit 1; }
|
||||
project_id="${GITLAB_PROJECT//\//%2F}"
|
||||
api="https://gitlab.com/api/v4/projects/${project_id}"
|
||||
title=$(jq -r '.name // .tag_name' release.json)
|
||||
notes=$(jq -r '.body // ""' release.json)
|
||||
payload=$(jq -n --arg tag "$TAG" --arg title "$title" --arg notes "$notes" \
|
||||
'{tag_name:$tag, name:$title, description:$notes}')
|
||||
|
||||
# Tags are already mirrored by GitLab's built-in repository mirror.
|
||||
curl -fsSL -X POST -H "PRIVATE-TOKEN: $GITLAB_PAT" \
|
||||
-H 'Content-Type: application/json' --data "$payload" \
|
||||
"${api}/releases" || \
|
||||
curl -fsSL -X PUT -H "PRIVATE-TOKEN: $GITLAB_PAT" \
|
||||
-H 'Content-Type: application/json' --data "$payload" \
|
||||
"${api}/releases/${TAG}"
|
||||
|
||||
for file in assets/*; do
|
||||
[ -f "$file" ] || continue
|
||||
upload=$(curl -fsSL -X POST -H "PRIVATE-TOKEN: $GITLAB_PAT" \
|
||||
-F "file=@$file" "${api}/uploads")
|
||||
url="https://gitlab.com/${GITLAB_PROJECT}$(jq -r '.url' <<< "$upload")"
|
||||
name=$(basename "$file")
|
||||
link=$(jq -n --arg name "$name" --arg url "$url" \
|
||||
'{name:$name, url:$url, link_type:"other"}')
|
||||
curl -fsSL -X POST -H "PRIVATE-TOKEN: $GITLAB_PAT" \
|
||||
-H 'Content-Type: application/json' --data "$link" \
|
||||
"${api}/releases/${TAG}/assets/links" || true
|
||||
done
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,4 +7,5 @@ sandbox/**
|
||||
|
||||
personal/
|
||||
.*
|
||||
!.gitignore
|
||||
!.gitignore
|
||||
!.github/
|
||||
24
README.md
24
README.md
@@ -216,6 +216,30 @@ Full docs at **[dcr.dexoron.su](https://dcr.dexoron.su)** or in the [`docs/`](do
|
||||
|
||||
---
|
||||
|
||||
## Repository Mirrors
|
||||
|
||||
The primary repository is hosted on GitHub. The following mirrors are available for source code and releases:
|
||||
|
||||
| Region | Mirror | Contents |
|
||||
|---|---|---|
|
||||
| Russia | [GitVerse](https://gitverse.ru/dcr_labs/dcr) **(recommended)** | Source code and releases |
|
||||
| Russia | [SourceCraft](https://sourcecraft.dev/dexoron-dev/dcr) | Source code and releases |
|
||||
| Worldwide | [SourceForge](https://sourceforge.net/projects/dcr-tool/) **(recommended)** | Source code and releases |
|
||||
| Worldwide | [GitLab](https://gitlab.com/dexoron-dev/dcr-tool/dcr) | Source code and releases |
|
||||
|
||||
---
|
||||
|
||||
## VS Code Extension
|
||||
|
||||
Install the recommended [DCR extension by Dexoron-Labs](https://marketplace.visualstudio.com/items?itemName=Dexoron-Labs.dcr) for VS Code. Do not install Microsoft C/C++ extensions for DCR projects; DCR uses `clangd` instead. If you need debugging with Microsoft's debugger, use MS C/C++ only for its debugger component.
|
||||
|
||||
Recommended companion extensions:
|
||||
|
||||
- [Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml)
|
||||
- [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), or MS C/C++ for debugger support only
|
||||
|
||||
---
|
||||
|
||||
## Contributors
|
||||
|
||||
<div align="center">
|
||||
|
||||
@@ -6,6 +6,13 @@ sidebar_label: IDE Integration
|
||||
|
||||
## VS Code
|
||||
|
||||
Install the recommended [DCR extension by Dexoron-Labs](https://marketplace.visualstudio.com/items?itemName=Dexoron-Labs.dcr). Do not install Microsoft C/C++ extensions for DCR projects: DCR uses `clangd`. MS C/C++ is acceptable only when you need its debugger.
|
||||
|
||||
Recommended companion extensions:
|
||||
|
||||
- [Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml)
|
||||
- [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), or MS C/C++ for debugger support only
|
||||
|
||||
```bash
|
||||
dcr gen vscode
|
||||
```
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Sync all GitHub Releases (with assets) to GitLab Releases."""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
import uuid
|
||||
|
||||
GL_TOKEN = os.environ.get("GL_TOKEN")
|
||||
if not GL_TOKEN:
|
||||
print("FATAL: GL_TOKEN environment variable not set", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
GL_PROJECT = "dexoron-studio%2Fdcr"
|
||||
GL_PROJECT_RAW = "dexoron-studio/dcr"
|
||||
GL_API = "https://gitlab.com/api/v4"
|
||||
GH_REPO = "dexoron/dcr"
|
||||
|
||||
|
||||
def gl_api(method, path, data=None, filepath=None, retries=5):
|
||||
url = f"{GL_API}/{path}"
|
||||
headers = {"PRIVATE-TOKEN": GL_TOKEN}
|
||||
|
||||
if data is not None and filepath is None:
|
||||
headers["Content-Type"] = "application/json"
|
||||
body = json.dumps(data).encode()
|
||||
elif filepath:
|
||||
boundary = uuid.uuid4().hex
|
||||
with open(filepath, "rb") as f:
|
||||
fdata = f.read()
|
||||
fname = os.path.basename(filepath)
|
||||
parts = []
|
||||
parts.append(f"--{boundary}".encode())
|
||||
parts.append(f'Content-Disposition: form-data; name="file"; filename="{fname}"'.encode())
|
||||
parts.append(b"Content-Type: application/octet-stream")
|
||||
parts.append(b"")
|
||||
parts.append(fdata)
|
||||
parts.append(f"--{boundary}--".encode())
|
||||
parts.append(b"")
|
||||
body = b"\r\n".join(parts)
|
||||
headers["Content-Type"] = f"multipart/form-data; boundary={boundary}"
|
||||
else:
|
||||
body = None
|
||||
|
||||
for attempt in range(retries):
|
||||
try:
|
||||
req = urllib.request.Request(url, data=body, headers=headers, method=method)
|
||||
with urllib.request.urlopen(req) as resp:
|
||||
text = resp.read().decode()
|
||||
return json.loads(text) if text else None
|
||||
except urllib.error.HTTPError as e:
|
||||
body_text = e.read().decode() if e.fp else ""
|
||||
if e.code in (409, 429) and attempt < retries - 1:
|
||||
time.sleep(3)
|
||||
continue
|
||||
if attempt < retries - 1:
|
||||
time.sleep(1)
|
||||
continue
|
||||
print(f" HTTP {e.code}: {body_text[:300]}", file=sys.stderr)
|
||||
return None
|
||||
except Exception as e:
|
||||
if attempt < retries - 1:
|
||||
time.sleep(1)
|
||||
continue
|
||||
print(f" Error: {e}", file=sys.stderr)
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
def download_file(url, dest):
|
||||
with urllib.request.urlopen(url) as resp:
|
||||
with open(dest, "wb") as f:
|
||||
f.write(resp.read())
|
||||
|
||||
|
||||
# --- MAIN ---
|
||||
print("Fetching GitHub releases...")
|
||||
with urllib.request.urlopen(f"https://api.github.com/repos/{GH_REPO}/releases?per_page=50") as r:
|
||||
gh_releases = json.loads(r.read().decode())
|
||||
|
||||
print(f"Found {len(gh_releases)} releases on GitHub")
|
||||
|
||||
# Reverse to process oldest first (GitHub returns newest first)
|
||||
gh_releases.reverse()
|
||||
|
||||
print("Fetching existing GitLab releases and their assets...")
|
||||
existing = gl_api("GET", f"projects/{GL_PROJECT}/releases?per_page=100") or []
|
||||
existing = existing if isinstance(existing, list) else []
|
||||
|
||||
# Build map: tag -> set of existing asset names
|
||||
gl_assets = {}
|
||||
for rel in existing:
|
||||
tag = rel["tag_name"]
|
||||
links = rel.get("assets", {}).get("links", []) or rel.get("assets", {}).get("sources", []) or []
|
||||
gl_assets[tag] = {l.get("name", "") for l in links if isinstance(l, dict)}
|
||||
# Also get the release description to check if it needs updating
|
||||
gl_assets[tag + "__desc"] = rel.get("description", "")
|
||||
|
||||
print(f"Existing GitLab releases: {len(existing)}")
|
||||
|
||||
download_dir = "/tmp/gh-assets"
|
||||
os.makedirs(download_dir, exist_ok=True)
|
||||
|
||||
# Reverse: process older first so newer releases with many assets get their description too
|
||||
# Actually, process in original order
|
||||
total = len(gh_releases)
|
||||
for i, rel in enumerate(gh_releases):
|
||||
tag = rel["tag_name"]
|
||||
body = rel.get("body", "") or ""
|
||||
assets = rel.get("assets", [])
|
||||
if isinstance(assets, dict):
|
||||
assets = assets.get("nodes", []) or []
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print(f"[{i+1}/{total}] {tag} ({len(assets)} assets)")
|
||||
|
||||
# Create or update release
|
||||
existing_tag = tag in gl_assets
|
||||
if not existing_tag:
|
||||
print(f" Creating release...")
|
||||
result = gl_api("POST", f"projects/{GL_PROJECT}/releases", data={
|
||||
"tag_name": tag,
|
||||
"name": rel.get("name", tag),
|
||||
"description": body,
|
||||
"ref": "master",
|
||||
})
|
||||
if result is None:
|
||||
print(f" FAILED — skip")
|
||||
continue
|
||||
print(f" OK")
|
||||
else:
|
||||
# Update description if needed
|
||||
existing_desc = gl_assets.get(tag + "__desc", "")
|
||||
if body and body != existing_desc:
|
||||
print(f" Updating description...")
|
||||
gl_api("PUT", f"projects/{GL_PROJECT}/releases/{urllib.request.quote(tag, safe='')}",
|
||||
data={"description": body})
|
||||
|
||||
existing_links = gl_assets.get(tag, set())
|
||||
|
||||
for j, asset in enumerate(assets):
|
||||
aname = asset.get("name", "")
|
||||
aurl = asset.get("browser_download_url", "")
|
||||
if not aurl:
|
||||
continue
|
||||
|
||||
if aname in existing_links:
|
||||
print(f" [{j+1}/{len(assets)}] {aname} — already exists")
|
||||
continue
|
||||
|
||||
fpath = os.path.join(download_dir, aname)
|
||||
print(f" [{j+1}/{len(assets)}] {aname}...", end=" ", flush=True)
|
||||
|
||||
# Download from GitHub
|
||||
try:
|
||||
download_file(aurl, fpath)
|
||||
except Exception as e:
|
||||
print(f"download failed: {e}")
|
||||
continue
|
||||
|
||||
# Upload to GitLab
|
||||
up = gl_api("POST", f"projects/{GL_PROJECT}/uploads", filepath=fpath)
|
||||
if not up or "url" not in up:
|
||||
size_mb = os.path.getsize(fpath) / (1024 * 1024)
|
||||
print(f"upload failed ({size_mb:.1f} MB)")
|
||||
os.remove(fpath)
|
||||
continue
|
||||
|
||||
file_url = up["url"]
|
||||
full_url = f"https://gitlab.com/{GL_PROJECT_RAW}{file_url}"
|
||||
|
||||
# Link asset to release
|
||||
encoded_tag = urllib.request.quote(tag, safe='')
|
||||
link = gl_api("POST",
|
||||
f"projects/{GL_PROJECT}/releases/{encoded_tag}/assets/links",
|
||||
data={"name": aname, "url": full_url},
|
||||
retries=5)
|
||||
if link:
|
||||
print(f"linked")
|
||||
existing_links.add(aname)
|
||||
else:
|
||||
print(f"link failed")
|
||||
|
||||
os.remove(fpath)
|
||||
|
||||
time.sleep(0.3)
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print("Done!")
|
||||
Reference in New Issue
Block a user