19 Commits

Author SHA1 Message Date
admin 5c54e23b0a Merge pull request 'fix: allow insecure nuget push connections' (#24) from feat/ai_code_review into develop
Reviewed-on: #24
2026-05-18 04:33:59 +00:00
AI Review Bot a6fdb07302 chore: update ai-review findings [ai-review-bot][success] 2026-05-18 04:33:41 +00:00
jiantw83 a9e957db63 fix: allow insecure nuget push connections 2026-05-18 04:31:44 +00:00
jiantw83 8e278659c0 Merge pull request 'fix: escape section separator printf' (#22) from feat/ai_code_review into develop
Reviewed-on: #22
2026-05-18 04:07:09 +00:00
AI Review Bot 6192b2099d chore: update ai-review findings [ai-review-bot][success] 2026-05-18 04:06:58 +00:00
jiantw83 83da83560c fix: escape section separator printf 2026-05-18 04:05:03 +00:00
jiantw83 3dc683b58d Merge pull request 'fix: adjust workflow review permissions' (#20) from feat/ai_code_review into develop
Reviewed-on: #20
2026-05-16 15:38:19 +00:00
jiantw83 28e240ce56 chore: triage review findings 2026-05-16 15:36:40 +00:00
AI Review Bot e6eaa224c6 chore: update ai-review findings [ai-review-bot][failure] 2026-05-16 15:33:15 +00:00
jiantw83 739735ffc1 chore: triage review findings 2026-05-16 15:31:25 +00:00
AI Review Bot d17d2614f8 chore: update ai-review findings [ai-review-bot][failure] 2026-05-16 15:27:38 +00:00
jiantw83 f7686a3b2f refactor: tidy nuget push output 2026-05-16 15:26:05 +00:00
jiantw83 325bedfc34 fix: adjust workflow review permissions 2026-05-16 15:24:52 +00:00
jiantw83 76edcc83f0 feat: update master.yaml job names and add review.yaml for AI code review 2026-05-13 03:17:00 +00:00
jiantw83 ac2ea2a9a5 更新 action.yaml
傳入存取權杖
2026-05-06 00:37:37 +00:00
Jeffery ffaea10f44 feat: 優先取得使用者的秘密參數,次則 Gitea 預設的 Token 2026-03-25 15:00:57 +08:00
jiantw83 cd0edec737 更新 action.yaml 2026-03-25 06:41:42 +00:00
jiantw83 82d3f78536 更新 action.yaml 2026-03-25 02:46:09 +00:00
jiantw83 9a90a92c0f 更新 Dockerfile 2026-03-23 10:10:20 +00:00
16 changed files with 423 additions and 52 deletions
+14
View File
@@ -0,0 +1,14 @@
# Triage Findings
When the task is to triage review findings, follow this workflow:
1. Merge all findings into one list.
2. Remove duplicates.
3. Sort by severity: `critical` -> `warning` -> `info`.
4. Renumber from 1 after sorting.
5. Fix real issues with the smallest safe change.
6. Add false positives to `.gitea/ai-review/exclusions.json`, preserving the original wording, language, and semantics as much as possible.
7. Add or update tests when behavior changes.
8. Re-check the issue after each fix.
Use the repo-local `triage-findings` skill for the same workflow when running in Codex.
+30
View File
@@ -0,0 +1,30 @@
---
name: triage-findings
description: Triage findings, fix real issues, and exclude false positives.
---
# Triage Findings
## Use
直接輸入:`triage-findings 問題原始檔(文字或截圖)`
## Workflow
1. Merge all findings.
2. Sort by severity:
- critical
- warning
- info
3. Renumber from 1.
4. Fix real issues.
5. Put false positives into `.gitea/ai-review/exclusions.json` as a top-level JSON array, preserving the original wording, language, and semantics as much as possible. Do not wrap the array in `exclusions` or `excluded_findings`.
6. Add tests when behavior changes.
## Output Rules
- Keep the final list short.
- Keep numbering contiguous.
- Preserve file path, location, and fix.
- When writing exclusions, always output a top-level JSON array.
- When writing exclusions, prefer the original issue text over paraphrased rewrites.
+46
View File
@@ -0,0 +1,46 @@
---
name: triage-findings
description: Merge code-review findings, sort and renumber them by severity, resolve real issues, and move false positives into exclusions.
---
# Triage Findings
## When To Use
Use this skill when you receive multiple review findings, screenshots, comments, or issue lists that need to become one final triaged list.
It is also used when some findings are false positives and should be moved into the exclusions list.
## Workflow
1. Collect all findings into one list.
2. Merge duplicates into a single finding when they describe the same issue.
3. Sort the final list by severity:
- critical
- warning
- info
4. Renumber the sorted list from 1 upward.
5. Rewrite each finding concisely so the final list reads cleanly and consistently.
6. If a finding is a false positive, do not keep it in the final list.
7. Add false positives to the exclusions list as a top-level JSON array in `.gitea/ai-review/exclusions.json`, and preserve the original finding wording as much as possible, including language and semantics. Do not wrap the array in `exclusions` or `excluded_findings`.
## Resolution Flow
After the list is merged and ordered, resolve the remaining findings one by one.
1. Start from the highest severity item.
2. Identify the root cause in the relevant file or context.
3. Apply the smallest safe change that fixes the issue.
4. Add or update tests when behavior changes.
5. Re-check the issue after the change.
6. If the item is confirmed false positive, move it to exclusions instead of changing code.
7. Continue until the list is either fixed or explicitly excluded.
## Output Rules
- Keep the final findings list in severity order, then by any stable secondary order needed to make it readable.
- Keep numbering contiguous after filtering and merging.
- Preserve useful details like file path, location, and suggested fix.
- Keep exclusions entries minimal and consistent with the project schema.
- When writing exclusions, always output a top-level JSON array.
- When writing exclusions, prefer the original issue text and language; only paraphrase if needed to fit the schema.
- If the source already provides a severity or title, keep it unless it conflicts with the final ordering.
@@ -0,0 +1,4 @@
interface:
display_name: "Triage Findings"
short_description: "Triage, sort, fix, and exclude review findings"
default_prompt: "Use $triage-findings to merge review findings, sort and renumber them by severity, resolve real issues one by one, and add false positives to `.gitea/ai-review/exclusions.json` as a top-level JSON array."
+30
View File
@@ -0,0 +1,30 @@
---
name: triage-findings
description: Triage findings, fix real issues, and exclude false positives.
---
# Triage Findings
## Use
直接輸入:`triage-findings 問題原始檔(文字或截圖)`
## Workflow
1. Merge all findings.
2. Sort by severity:
- critical
- warning
- info
3. Renumber from 1.
4. Fix real issues.
5. Put false positives into `.gitea/ai-review/exclusions.json` as a top-level JSON array, preserving the original wording, language, and semantics as much as possible. Do not wrap the array in `exclusions` or `excluded_findings`.
6. Add tests when behavior changes.
## Output Rules
- Keep the final list short.
- Keep numbering contiguous.
- Preserve file path, location, and fix.
- When writing exclusions, always output a top-level JSON array.
- When writing exclusions, prefer the original issue text over paraphrased rewrites.
+110
View File
@@ -0,0 +1,110 @@
[
{
"level": "critical",
"role": "Aria",
"location": "Dockerfile",
"suggestion": "檔案末尾應包含一個空行,以符合 POSIX 規範並避免工具處理問題。"
},
{
"level": "warning",
"role": "Zara",
"location": "Dockerfile:10",
"suggestion": "在 `apt-get install` 命令中加入 `--no-install-recommends` 參數是一個很好的優化,它能減少安裝不必要的推薦套件,進而縮小 Docker 映像檔的體積。較小的映像檔能加快建置、推送與拉取的速度,並節省儲存空間。"
},
{
"level": "warning",
"role": "Maya",
"location": "entrypoint.sh:28-34",
"suggestion": "新增了 `require_index` 函數來驗證 `RELEASE_INDEX` 必須是非負整數。這是一個很好的改進,但需要為此新增測試案例,例如傳入非數字字串或負數,確保腳本能正確地捕捉錯誤並退出。"
},
{
"level": "warning",
"role": "Maya",
"location": "entrypoint.sh:83-87",
"suggestion": "新增了檢查解壓縮後是否找到 `.nupkg` 檔案的邏輯。這是一個重要的邊界條件處理,請為此新增測試案例,確保當成品中不包含 `.nupkg` 檔案時,腳本能正確地報錯並退出。"
},
{
"level": "info",
"role": "Zara",
"location": "entrypoint.sh:3",
"suggestion": "使用 `set -Eeuo pipefail` 是一個良好的 Shell 腳本實踐。它能確保腳本在遇到錯誤時立即終止 (`-e`)、未定義變數時報錯 (`-u`),並在管道命令中捕捉錯誤 (`-o pipefail`)。這提升了腳本的健壯性和可靠性,間接避免因錯誤導致的資源浪費。"
},
{
"level": "info",
"role": "Zara",
"location": "entrypoint.sh:40",
"suggestion": "在 `curl` 命令中加入 `-f` (fail fast) 參數,可以在 HTTP 錯誤時立即終止腳本,避免處理無效資料,提高腳本的穩定性。同時,`-L` (follow redirects) 參數確保能正確處理重定向,提升可靠性。"
},
{
"level": "info",
"role": "Zara",
"location": "entrypoint.sh:54",
"suggestion": "在 `unzip` 命令中使用 `-q` (quiet) 參數可以抑制詳細輸出,減少控制台 I/O,使日誌更簡潔。這是一個輕微的效能優化和日誌清理。"
},
{
"level": "info",
"role": "Aria",
"location": "entrypoint.sh",
"suggestion": "腳本內部變數從 `UPPER_SNAKE_CASE` (例如 `RELEASE_HEADER`) 變更為 `snake_case` (例如 `release_header`),這與 shell 腳本的常見慣例更一致,有助於區分環境變數和內部變數。此為風格改善。"
},
{
"level": "info",
"role": "Maya",
"location": "entrypoint.sh",
"suggestion": "此腳本經過重構後,錯誤處理和參數驗證變得更加健壯(例如使用 `set -Eeuo pipefail` 和自定義驗證函數)。為了確保這些改進的穩定性,建議導入一個輕量級的 shell 腳本測試框架(如 `bats` 或 `shunit2`),為所有關鍵函數和端到端流程編寫單元測試和整合測試,以覆蓋各種成功和失敗情境。"
},
{
"level": "critical",
"role": "Rex",
"location": "entrypoint.sh:L71 (舊版)",
"suggestion": "舊版腳本直接使用 `unzip \"$RELEASE_NAME\" -d output` 解壓縮檔案,存在 Zip Slip (路徑遍歷) 漏洞風險。惡意壓縮檔可能包含 `../../etc/passwd` 等路徑,導致任意檔案被覆蓋或寫入。新版腳本新增了 `validate_release_archive` 函數來檢查壓縮檔內容,有效防範此類攻擊,這是非常關鍵的安全改進。"
},
{
"level": "critical",
"role": "Rex",
"location": "entrypoint.sh:L90 (舊版)",
"suggestion": "舊版腳本在推送 NuGet 套件時使用了 `--allow-insecure-connections` 旗標,這意味著 `RUNNER_TOKEN` 可能會透過未加密的 HTTP 連線傳輸,容易被中間人攻擊竊取。新版腳本移除了此旗標,強制使用安全的 HTTPS 連線,這是非常重要的安全強化。應始終優先使用加密連線來傳輸敏感資料。"
},
{
"level": "critical",
"role": "Rex",
"location": "entrypoint.sh:L19-L26 (舊版), L69 (舊版)",
"suggestion": "舊版腳本直接將敏感的 `RUNNER_TOKEN` 變數值輸出到標準輸出,這可能導致令牌洩漏到日誌或執行環境中。新版腳本透過 `require_value` 函數對敏感變數進行遮罩處理,是一個重要的安全改進。建議所有包含敏感資訊(如 API 金鑰、密碼、令牌)的變數在輸出時都應進行遮罩或避免直接輸出。"
},
{
"level": "warning",
"role": "Aria",
"location": "a/entrypoint.sh:3,6,27,30,32,35,40,43,45,48,50,53,55,58,60,63,66,68,71,74",
"suggestion": "腳本中的區塊標題格式不一致且手動維護。建議使用一個專門的函數來生成標準化的區塊標題,以提高一致性與可讀性。"
},
{
"level": "warning",
"role": "Aria",
"location": "a/entrypoint.sh:44,47",
"suggestion": "將變數內容傳遞給 `jq` 時,使用 `printf '%s'` 而非 `echo` 更為安全,因為 `echo` 在不同 shell 中對特殊字元(如反斜線)的處理可能不一致。"
},
{
"level": "warning",
"role": "Aria",
"location": "a/entrypoint.sh:62",
"suggestion": "`dotnet nuget push \"output/*.nupkg\"` 依賴 shell 的萬用字元展開,這在沒有匹配檔案或匹配檔案過多時可能導致錯誤。建議使用 `find` 命令安全地列出所有 `.nupkg` 檔案,並逐一推送,以提高腳本的健壯性。"
},
{
"level": "info",
"role": "Leo",
"location": "entrypoint.sh",
"suggestion": "腳本中包含多處硬編碼的繁體中文錯誤訊息(例如 `錯誤:...`)。若團隊成員或使用者可能來自不同語言背景,考慮將錯誤訊息國際化(例如,透過環境變數或外部設定檔提供不同語言版本),或統一使用英文以提高通用性,有助於長期維護和跨文化協作。"
},
{
"level": "info",
"role": "Aria",
"location": "a/Dockerfile:5",
"suggestion": "在 Dockerfile 或腳本中,建議使用 `apt-get` 而非 `apt` 進行套件管理操作,因為 `apt-get` 在非互動式環境中行為更穩定且可預測。"
},
{
"level": "info",
"role": "Aria",
"location": "a/Dockerfile:9",
"suggestion": "空行不應包含額外的縮排空格,以保持格式一致性。"
}
]
+1
View File
@@ -0,0 +1 @@
[]
+4 -3
View File
@@ -1,10 +1,11 @@
name: CD
on:
push:
branches:
- master
jobs:
version:
name: "CD > 計算版本號"
name: 計算版本號
runs-on: ubuntu
outputs:
version: ${{ steps.version.outputs.version }}
@@ -13,14 +14,14 @@ jobs:
id: version
uses: https://gitea.jsc.idv.tw/actions/calculate-version@${{ vars.ACTION_CALCULATE_VERSION }}
release:
name: "CD > 發布專案"
name: 發布專案
runs-on: ubuntu
needs: version
steps:
- name: 發布專案
uses: akkuman/gitea-release-action@${{ vars.ACTION_RELEASE_VERSION }}
with:
tag_name: "v${{ needs.version.outputs.version }}"
tag_name: v${{ needs.version.outputs.version }}
- name: 清理成品
uses: https://gitea.jsc.idv.tw/actions/cleanup-release@${{ vars.ACTION_CLEANUP_RELEASE_VERSION }}
with:
+23
View File
@@ -0,0 +1,23 @@
name: AI
on:
pull_request:
branches-ignore:
- master
types: [opened, synchronize]
jobs:
code-review:
name: Code Review
runs-on: ubuntu
steps:
- name: AI Code Review
uses: https://gitea.jsc.idv.tw/actions/code-review@${{ vars.ACTION_CODE_REVIEW_VERSION }}
with:
GITEA_TOKEN: ${{ secrets.RUNNER_TOKEN }}
GITEA_COMMENT_TOKEN: ${{ secrets.GITEA_TOKEN }}
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }},${{ secrets.GEMINI_API_KEY_1 }},${{ secrets.GEMINI_API_KEY_2 }},${{ secrets.GEMINI_API_KEY_3 }},${{ secrets.GEMINI_API_KEY_4 }},${{ secrets.GEMINI_API_KEY_5 }},${{ secrets.GEMINI_API_KEY_6 }},${{ secrets.GEMINI_API_KEY_7 }},${{ secrets.GEMINI_API_KEY_8 }},${{ secrets.GEMINI_API_KEY_9 }},${{ secrets.GEMINI_API_KEY_10 }},${{ secrets.GEMINI_API_KEY_11 }},${{ secrets.GEMINI_API_KEY_12 }},${{ secrets.GEMINI_API_KEY_13 }},${{ secrets.GEMINI_API_KEY_14 }},${{ secrets.GEMINI_API_KEY_15 }},${{ secrets.GEMINI_API_KEY_16 }},${{ secrets.GEMINI_API_KEY_17 }},${{ secrets.GEMINI_API_KEY_18 }},${{ secrets.GEMINI_API_KEY_19 }}
GEMINI_BASE_URL: https://generativelanguage.googleapis.com/v1beta
GEMINI_MODEL: ${{ vars.GEMINI_MODEL }}
permissions:
contents: write
pull-requests: write
issues: write
+14
View File
@@ -0,0 +1,14 @@
# Triage Findings
Use the triage-finding workflow for review issue lists:
1. Merge findings into one list.
2. Remove duplicates.
3. Sort by severity: `critical` -> `warning` -> `info`.
4. Renumber from 1.
5. Fix real issues with the smallest safe change.
6. Put false positives into `.gitea/ai-review/exclusions.json`, preserving the original wording, language, and semantics as much as possible.
7. Add or update tests when behavior changes.
8. Re-check after each fix.
The full reusable skill lives in `.claude/skills/triage-findings/SKILL.md`.
+14
View File
@@ -0,0 +1,14 @@
# Triage Findings
Use the triage-finding workflow for review issue lists:
1. Merge findings into one list.
2. Remove duplicates.
3. Sort by severity: `critical` -> `warning` -> `info`.
4. Renumber from 1.
5. Fix real issues with the smallest safe change.
6. Put false positives into `.gitea/ai-review/exclusions.json` as a top-level JSON array, preserving the original wording, language, and semantics as much as possible. Do not wrap the array in `exclusions` or `excluded_findings`.
7. Add or update tests when behavior changes.
8. Re-check after each fix.
The reusable skill lives in `.gemini/skills/triage-findings/SKILL.md`.
+16
View File
@@ -0,0 +1,16 @@
# Triage Findings
When the task is to triage review findings, follow this workflow:
1. Merge all findings into one list.
2. Remove duplicates.
3. Sort by severity: `critical` -> `warning` -> `info`.
4. Renumber from 1 after sorting.
5. Fix real issues with the smallest safe change.
6. Add false positives to `.gitea/ai-review/exclusions.json`, preserving the original wording, language, and semantics as much as possible.
7. Add or update tests when behavior changes.
8. Re-check the issue after each fix.
Use the repo-local `triage-findings` skill for the same workflow when running in Codex.
Trigger it with `/triage-findings`.
+6 -5
View File
@@ -1,12 +1,13 @@
FROM mcr.microsoft.com/dotnet/sdk:10.0
# 更新並安裝必要工具後清理暫存檔案以減小映像檔大小
RUN apt update \
&& apt install -y curl jq unzip \
# 安裝必要工具,並清理 apt 快取以縮小映像檔
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl jq unzip \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
ENTRYPOINT ["/entrypoint.sh"]
+14
View File
@@ -0,0 +1,14 @@
# Triage Findings
Use the triage-finding workflow for review issue lists:
1. Merge findings into one list.
2. Remove duplicates.
3. Sort by severity: `critical` -> `warning` -> `info`.
4. Renumber from 1.
5. Fix real issues with the smallest safe change.
6. Put false positives into `.gitea/ai-review/exclusions.json`, preserving the original wording, language, and semantics as much as possible.
7. Add or update tests when behavior changes.
8. Re-check after each fix.
The reusable skill lives in `.gemini/skills/triage-findings/SKILL.md`.
+3 -1
View File
@@ -8,6 +8,8 @@ inputs:
RELEASE_INDEX:
description: '要推送的版本中第幾個成品,預設為 0'
default: 0
RUNNER_TOKEN:
description: '存取權杖'
runs:
using: 'docker'
image: 'Dockerfile'
@@ -16,5 +18,5 @@ runs:
GITEA_REPOSITORY: ${{ gitea.repository }}
RELEASE_VERSION: ${{ inputs.RELEASE_VERSION }}
RELEASE_INDEX: ${{ inputs.RELEASE_INDEX }}
RUNNER_TOKEN: ${{ secrets.RUNNER_TOKEN }}
RUNNER_TOKEN: ${{ inputs.RUNNER_TOKEN || secrets.RUNNER_TOKEN || secrets.GITEA_TOKEN }}
NUGET_AUTHOR: ${{ gitea.repository_owner }}
+94 -43
View File
@@ -1,75 +1,126 @@
#!/bin/bash
echo "=================================================="
set -Eeuo pipefail
echo "參數檢查"
section() {
printf '\n==================================================\n'
printf '%s\n' "$1"
printf -- '--------------------------------------------------\n'
}
echo "--------------------------------------------------"
require_value() {
local name="$1"
local value="$2"
local display_value="$value"
# 顯示 GITEA_SERVER_URL 參數,並檢查是否為空或 "null",如果是則輸出錯誤訊息並退出
echo "GITEA_SERVER_URL=$GITEA_SERVER_URL" && ([ -z "$GITEA_SERVER_URL" ] || [ "$GITEA_SERVER_URL" = "null" ]) && exit 1
case "$name" in
*TOKEN*|*SECRET*|*PASSWORD*|*PASS*|*KEY*)
display_value="***"
;;
esac
# 顯示 GITEA_REPOSITORY 參數,並檢查是否為空或 "null",如果是則輸出錯誤訊息並退出
echo "GITEA_REPOSITORY=$GITEA_REPOSITORY" && ([ -z "$GITEA_REPOSITORY" ] || [ "$GITEA_REPOSITORY" = "null" ]) && exit 1
printf '%s=%s\n' "$name" "$display_value"
# 顯示 RELEASE_VERSION 參數,並檢查是否為空或 "null",如果是則輸出錯誤訊息並退出
echo "RELEASE_VERSION=$RELEASE_VERSION" && ([ -z "$RELEASE_VERSION" ] || [ "$RELEASE_VERSION" = "null" ]) && exit 1
if [ -z "$value" ] || [ "$value" = "null" ]; then
printf '錯誤:%s 不可為空\n' "$name" >&2
exit 1
fi
}
# 顯示 RELEASE_INDEX 參數,並檢查是否為空或 "null",如果是則輸出錯誤訊息並退出
echo "RELEASE_INDEX=$RELEASE_INDEX" && ([ -z "$RELEASE_INDEX" ] || [ "$RELEASE_INDEX" = "null" ]) && exit 1
validate_release_archive() {
local archive="$1"
local archive_entries
local entry
local normalized_entry
# 顯示 RUNNER_TOKEN 參數,並檢查是否為空或 "null",如果是則輸出錯誤訊息並退出
echo "RUNNER_TOKEN=$RUNNER_TOKEN" && ([ -z "$RUNNER_TOKEN" ] || [ "$RUNNER_TOKEN" = "null" ]) && exit 1
if ! archive_entries="$(unzip -Z1 "$archive")"; then
printf '錯誤:無法讀取壓縮檔:%s\n' "$archive" >&2
exit 1
fi
# 顯示 NUGET_AUTHOR 參數,並檢查是否為空或 "null",如果是則輸出錯誤訊息並退出
echo "NUGET_AUTHOR=$NUGET_AUTHOR" && ([ -z "$NUGET_AUTHOR" ] || [ "$NUGET_AUTHOR" = "null" ]) && exit 1
while IFS= read -r entry; do
[ -z "$entry" ] && continue
echo "=================================================="
normalized_entry="${entry//\\//}"
echo "取得成品連結"
case "$normalized_entry" in
/*|../*|*/../*|*/..|..)
printf '錯誤:壓縮檔包含不安全路徑:%s\n' "$entry" >&2
exit 1
;;
esac
done <<EOF
$archive_entries
EOF
}
echo "--------------------------------------------------"
require_index() {
local value="$1"
# 組合 RELEASE_HEADER 參數,並顯示出來
RELEASE_HEADER="Authorization: token $RUNNER_TOKEN" && echo "RELEASE_HEADER=$RELEASE_HEADER"
if [[ ! "$value" =~ ^[0-9]+$ ]]; then
printf '錯誤:RELEASE_INDEX 必須是非負整數\n' >&2
exit 1
fi
}
# 組合 RELEASE_URL 參數,並顯示出來
RELEASE_URL="$GITEA_SERVER_URL/api/v1/repos/$GITEA_REPOSITORY/releases/tags/v$RELEASE_VERSION" && echo "RELEASE_URL=$RELEASE_URL"
section "參數檢查"
require_value "GITEA_SERVER_URL" "${GITEA_SERVER_URL:-}"
require_value "GITEA_REPOSITORY" "${GITEA_REPOSITORY:-}"
require_value "RELEASE_VERSION" "${RELEASE_VERSION:-}"
require_value "RELEASE_INDEX" "${RELEASE_INDEX:-}"
require_index "${RELEASE_INDEX:-}"
require_value "RUNNER_TOKEN" "${RUNNER_TOKEN:-}"
require_value "NUGET_AUTHOR" "${NUGET_AUTHOR:-}"
# 取得成品資訊
RELEASE_JSON="$(curl -s -H "$RELEASE_HEADER" "$RELEASE_URL")"
section "取得成品連結"
# 從成品資訊取得名稱
RELEASE_NAME="$(echo "$RELEASE_JSON" | jq -r ".assets[$RELEASE_INDEX].name")" && echo "RELEASE_NAME=$RELEASE_NAME" && ([ -z "$RELEASE_NAME" ] || [ "$RELEASE_NAME" = "null" ]) && exit 1
release_header="Authorization: token $RUNNER_TOKEN"
release_api_url="$GITEA_SERVER_URL/api/v1/repos/$GITEA_REPOSITORY/releases/tags/v$RELEASE_VERSION"
# 從成品資訊取得連結
RELEASE_URL="$(echo "$RELEASE_JSON" | jq -r ".assets[$RELEASE_INDEX].browser_download_url")" && echo "RELEASE_URL=$RELEASE_URL" && ([ -z "$RELEASE_URL" ] || [ "$RELEASE_URL" = "null" ]) && exit 1
printf 'RELEASE_API_URL=%s\n' "$release_api_url"
echo "=================================================="
release_json="$(curl -fsSL -H "$release_header" "$release_api_url")"
release_asset_path=".assets[$RELEASE_INDEX]"
echo "下載成品"
release_name="$(printf '%s' "$release_json" | jq -r "$release_asset_path.name")"
require_value "RELEASE_NAME" "$release_name"
echo "--------------------------------------------------"
release_url="$(printf '%s' "$release_json" | jq -r "$release_asset_path.browser_download_url")"
require_value "RELEASE_URL" "$release_url"
curl -H "$RELEASE_HEADER" "$RELEASE_URL" -o "$RELEASE_NAME"
section "下載成品"
echo "=================================================="
curl -fsSL -H "$release_header" "$release_url" -o "$release_name"
printf '已下載:%s\n' "$release_name"
echo "解壓縮成品"
section "解壓縮成品"
echo "--------------------------------------------------"
rm -rf output
mkdir -p output
validate_release_archive "$release_name"
unzip -q "$release_name" -d output
printf '已解壓縮到:%s\n' "output"
unzip "$RELEASE_NAME" -d output
section "推送 NUGET 套件"
echo "=================================================="
nuget_source="$GITEA_SERVER_URL/api/packages/$NUGET_AUTHOR/nuget/index.json"
printf 'NUGET_SOURCE=%s\n' "$nuget_source"
echo "推送 NUGET 套件"
mapfile -t nuget_packages < <(find output -type f -name '*.nupkg' | sort)
echo "--------------------------------------------------"
if [ "${#nuget_packages[@]}" -eq 0 ]; then
printf '錯誤:找不到 .nupkg 檔案\n' >&2
exit 1
fi
# 組合 NUGET_SOURCE 參數,並顯示出來
NUGET_SOURCE="$GITEA_SERVER_URL/api/packages/$NUGET_AUTHOR/nuget/index.json" && echo "NUGET_SOURCE=$NUGET_SOURCE"
for nuget_package in "${nuget_packages[@]}"; do
printf 'NUGET_PACKAGE=%s\n' "$nuget_package"
dotnet nuget push "output/*.nupkg" --source "$NUGET_SOURCE" --api-key "$RUNNER_TOKEN" --skip-duplicate --allow-insecure-connections
dotnet nuget push "$nuget_package" \
--source "$nuget_source" \
--api-key "$RUNNER_TOKEN" \
--skip-duplicate \
--allow-insecure-connections
done
echo "=================================================="
section "完成"