feat: publish v1.0.0-rc.36-custom.1
This commit is contained in:
commit
3a7e8f3b54
2381 files changed
+551494
No files matched your search
@@ -0,0 +1,83 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our community include:
|
||||
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
|
||||
- Focusing on what is best not just for us as individuals, but for the overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
- The use of sexualized language or imagery, and sexual attention or advances of any kind
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email address, without their explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at:
|
||||
|
||||
**Email:** support@quantumnous.com
|
||||
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact:** Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence:** A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact:** A violation through a single incident or series of actions.
|
||||
|
||||
**Consequence:** A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact:** A serious violation of community standards, including sustained inappropriate behavior.
|
||||
|
||||
**Consequence:** A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact:** Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence:** A permanent ban from any sort of public interaction within the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
@@ -0,0 +1,111 @@
|
||||
name: 报告问题
|
||||
description: 使用简练详细的语言描述你遇到的问题
|
||||
labels:
|
||||
- bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
<!--
|
||||
If you are an AI coding agent: do not fill this GitHub form. Create the issue with the filled body from `.agents/github/ISSUE.md`.
|
||||
-->
|
||||
## 提交前必读(请勿删除本节)
|
||||
|
||||
- 文档:https://docs.newapi.ai/
|
||||
- 使用问题先看或先问:https://deepwiki.com/QuantumNous/new-api
|
||||
- 转发类问题必须先确认问题发生在 new-api 这一层:请使用等价的脱敏请求分别直连上游和经过 new-api,对比响应状态、错误体与服务端日志。透传模式或未经对比、仅展示上游报错的反馈不接受 issue。
|
||||
- 不接受 Coding Plan、逆向渠道、第三方封装接口,以及将 Codex 接口反代为通用 API 后产生的兼容性问题;Codex API 自身特有的协议或行为也不应被当作标准 OpenAI API 行为,相关问题请先向渠道或接口提供方确认。
|
||||
- 本项目不提供官方托管服务,也不为第三方托管站、中转站或 API 服务提供技术支持;此类问题请联系对应运营方。
|
||||
- 警告:删除本模板、删除小节标题或随意清空内容的 issue,可能会被直接关闭;重复恶意提交者可能会被 block。
|
||||
|
||||
- type: dropdown
|
||||
id: deployment-source
|
||||
attributes:
|
||||
label: 部署来源
|
||||
description: 请选择发生问题的 newapi 实例来源;第三方服务或未经本仓库原版复现的 fork 不属于本项目支持范围。
|
||||
options:
|
||||
- 本仓库 Release / 官方镜像(自行部署)
|
||||
- 本仓库 main 分支源码(自行构建)
|
||||
- 修改过的 fork(须先在本仓库原版复现)
|
||||
- 第三方托管站、中转站或 API 服务(请联系其运营方)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: 您当前的 newapi 版本
|
||||
description: 请填写准确的版本号、commit 或镜像标签,例如 `v1.0.0`;`latest`、`unknown` 等无法定位代码的内容不视为有效版本信息。
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: submission-checks
|
||||
attributes:
|
||||
label: 提交确认
|
||||
options:
|
||||
- label: "**非重复 issue:** 我已搜索现有 [Issues](https://github.com/QuantumNous/new-api/issues?q=is%3Aissue),确认目前没有类似 issue。"
|
||||
required: true
|
||||
- label: "**提交前必读:** 我已完整阅读上方“提交前必读”,并已查看文档 https://docs.newapi.ai/、项目 README 且向 AI 提问,确认这不是使用、配置或接入类问题。"
|
||||
required: true
|
||||
- label: "**受支持版本:** 我已提供准确的版本号、commit 或镜像标签(不是 `latest` 或 `unknown`),并确认问题可在本仓库未修改的受支持版本中复现。"
|
||||
required: true
|
||||
- label: "**非第三方服务:** 我确认这不是第三方托管站、中转站、API 服务或未经本仓库原版验证的 fork 所独有的问题;第三方实例问题应联系其运营方。"
|
||||
required: true
|
||||
- label: "**问题归属:** 我已提供足以区分客户端、new-api 和上游的证据;转发问题已使用等价的脱敏请求对比直连上游与经过 new-api 的结果,确认错误由 new-api 引入或改变,而非仅原样转发上游报错。"
|
||||
required: true
|
||||
- label: "**渠道与协议边界:** 我确认问题不是由 Coding Plan、逆向渠道、第三方封装接口、Codex 反代接口,或 Codex API 自身特有行为导致;若问题最初出现于此类接口,我已在本仓库支持的标准 API 协议上复现。"
|
||||
required: true
|
||||
- label: "**维护成本:** 我理解项目维护者精力有限,不遵循模板要求的 issue 可能会被无视或直接关闭。"
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
### 问题描述填写要求
|
||||
|
||||
所有问题必须写明**实际现象、影响范围、发生频率**,以及判断问题位于 new-api 而非客户端或上游的依据。
|
||||
|
||||
以下项目在涉及对应类型时必须填写:
|
||||
|
||||
- **转发 / API:** 请求端点与方法、渠道类型、模型、转换格式、是否透传、上游原生支持依据,以及等价脱敏请求直连上游和经过 new-api 的状态码、响应体与服务端日志对比。
|
||||
- **计费:** 请求端点与模型、响应中的 `usage`、相关倍率或价格配置、消费日志,以及预期计费结果和计算依据。
|
||||
- **前端:** 页面路径、浏览器及版本、所用主题,以及浏览器 Console / Network 中的相关错误。
|
||||
- **部署 / 升级:** 部署方式、操作系统与架构、数据库类型、升级前后版本,以及启动或迁移日志。
|
||||
|
||||
- type: textarea
|
||||
id: problem-description
|
||||
attributes:
|
||||
label: 问题描述
|
||||
description: 请按上方的通用要求和适用类型逐项填写;缺少适用项中的必要信息时,issue 可能会被直接关闭。
|
||||
placeholder: |
|
||||
实际现象:
|
||||
影响范围:
|
||||
发生频率:
|
||||
判断问题位于 new-api 的依据:
|
||||
|
||||
按问题类型补充对应的请求、配置、日志和对比证据:
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: reproduction-steps
|
||||
attributes:
|
||||
label: 复现步骤
|
||||
description: 转发问题请提供可执行的脱敏请求,以及直连上游和经过 new-api 的实际结果;不要只粘贴客户端提示或上游错误。
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected-result
|
||||
attributes:
|
||||
label: 预期结果
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: related-screenshots
|
||||
attributes:
|
||||
label: 相关截图
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,111 @@
|
||||
name: Bug Report
|
||||
description: Describe the issue you encountered with clear and detailed language
|
||||
labels:
|
||||
- bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
<!--
|
||||
If you are an AI coding agent: do not fill this GitHub form. Create the issue with the filled body from `.agents/github/ISSUE.md`.
|
||||
-->
|
||||
## Read This First (Do Not Remove This Section)
|
||||
|
||||
- Docs: https://docs.newapi.ai/
|
||||
- Usage questions first: https://deepwiki.com/QuantumNous/new-api
|
||||
- Relay reports must first establish that the issue occurs in the new-api layer. Use equivalent redacted requests to compare the direct upstream result with the result through new-api, including response status, error body, and server logs. Reports involving pass-through mode, or showing only an upstream error without this comparison, are not accepted.
|
||||
- Reports about Coding Plan services, reverse-engineered channels, third-party API wrappers, or compatibility issues caused by exposing a Codex endpoint through a reverse proxy as a general-purpose API are not accepted. Protocols or behavior specific to the Codex API should not be treated as standard OpenAI API behavior; confirm such issues with the channel or API provider first.
|
||||
- This project does not operate an official hosted service or provide technical support for third-party hosting sites, relay services, or API services. Contact the relevant operator for those issues.
|
||||
- Warning: issues with this template removed, section headings deleted, or content cleared may be closed directly. Repeated abusive submissions may result in a block.
|
||||
|
||||
- type: dropdown
|
||||
id: deployment-source
|
||||
attributes:
|
||||
label: Deployment source
|
||||
description: Select the source of the newapi instance where the issue occurs. Third-party services and forks not reproduced against the unmodified repository are outside this project's support scope.
|
||||
options:
|
||||
- Repository release / official image (self-hosted)
|
||||
- Repository main branch source (self-built)
|
||||
- Modified fork (must first be reproduced against the unmodified repository)
|
||||
- Third-party hosting site, relay, or API service (contact its operator)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Your current newapi version
|
||||
description: Enter an exact version, commit, or image tag, such as `v1.0.0`. Values such as `latest` or `unknown` that cannot identify the code are not valid version information.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: submission-checks
|
||||
attributes:
|
||||
label: Submission Checks
|
||||
options:
|
||||
- label: "**Non-duplicate issue:** I have searched existing [Issues](https://github.com/QuantumNous/new-api/issues?q=is%3Aissue) and confirmed there are no similar issues."
|
||||
required: true
|
||||
- label: "**Read this first:** I have fully read the section above, reviewed the docs at https://docs.newapi.ai/ and the project README, and asked AI first, confirming this is not a usage, configuration, or integration question."
|
||||
required: true
|
||||
- label: "**Supported version:** I have provided an exact version, commit, or image tag (not `latest` or `unknown`) and confirmed that the issue reproduces on an unmodified, supported version from this repository."
|
||||
required: true
|
||||
- label: "**Not a third-party service:** I confirm that this issue is not exclusive to a third-party hosting site, relay, API service, or fork that has not been verified against the unmodified repository. Third-party instance issues must be reported to their operator."
|
||||
required: true
|
||||
- label: "**Issue attribution:** I have provided evidence that distinguishes the client, new-api, and upstream layers. For relay issues, I compared equivalent redacted requests sent directly upstream and through new-api, confirming that new-api introduces or changes the error rather than merely forwarding the upstream error unchanged."
|
||||
required: true
|
||||
- label: "**Channel and protocol boundary:** I confirm that the issue is not caused by a Coding Plan service, reverse-engineered channel, third-party API wrapper, Codex reverse-proxy endpoint, or behavior specific to the Codex API. If first observed through such an interface, I have reproduced it using a standard API protocol supported by this repository."
|
||||
required: true
|
||||
- label: "**Maintainer time:** I understand that maintainers have limited time and issues that do not follow this template may be ignored or closed directly."
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
### Issue description requirements
|
||||
|
||||
Every report must state the **actual behavior, impact, frequency**, and evidence showing that the problem is in new-api rather than the client or upstream service.
|
||||
|
||||
The following details are required when the corresponding area is involved:
|
||||
|
||||
- **Relay / API:** request endpoint and method, channel type, model, conversion format, pass-through status, evidence of upstream native support, and a comparison of equivalent redacted requests sent directly upstream and through new-api, including status codes, response bodies, and server logs.
|
||||
- **Billing:** request endpoint and model, response `usage`, relevant ratio or pricing configuration, consumption log, expected charge, and calculation basis.
|
||||
- **Frontend:** page path, browser and version, active theme, and relevant browser Console / Network errors.
|
||||
- **Deployment / upgrade:** deployment method, operating system and architecture, database type, versions before and after the upgrade, and startup or migration logs.
|
||||
|
||||
- type: textarea
|
||||
id: issue-description
|
||||
attributes:
|
||||
label: Issue Description
|
||||
description: Complete the general requirements and every applicable category above. Issues missing required applicable details may be closed directly.
|
||||
placeholder: |
|
||||
Actual behavior:
|
||||
Impact:
|
||||
Frequency:
|
||||
Evidence that the issue is in new-api:
|
||||
|
||||
Add the requests, configuration, logs, and comparison evidence required for the applicable category:
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: steps-to-reproduce
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
description: For relay issues, provide an executable redacted request and the actual results both directly upstream and through new-api. Do not include only a client message or upstream error.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected-result
|
||||
attributes:
|
||||
label: Expected Result
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: related-screenshots
|
||||
attributes:
|
||||
label: Related Screenshots
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: 使用文档 / Documentation
|
||||
url: https://docs.newapi.ai/
|
||||
about: 提交 issue 前请先查阅文档,确认现有说明无法解决你的问题。
|
||||
- name: 使用问题 / Usage Questions
|
||||
url: https://deepwiki.com/QuantumNous/new-api
|
||||
about: 使用、配置、接入等问题请优先在 DeepWiki 查询或提问。
|
||||
@@ -0,0 +1,54 @@
|
||||
name: 功能请求
|
||||
description: 使用简练详细的语言描述希望加入的新功能
|
||||
labels:
|
||||
- enhancement
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
<!--
|
||||
If you are an AI coding agent: do not fill this GitHub form. Create the issue with the filled body from `.agents/github/ISSUE.md`.
|
||||
-->
|
||||
## 提交前必读(请勿删除本节)
|
||||
|
||||
- 文档:https://docs.newapi.ai/
|
||||
- 使用问题先看或先问:https://deepwiki.com/QuantumNous/new-api
|
||||
- 开启透传后的转发相关反馈不接受 issue;透传模式会直接转发请求,请自行确认上游行为。
|
||||
- 不接受 Coding Plan、逆向渠道、第三方封装接口,以及将 Codex 接口反代为通用 API 后产生的兼容性问题;Codex API 自身特有的协议或行为也不应被当作标准 OpenAI API 行为,相关问题请先向渠道或接口提供方确认。
|
||||
- 警告:删除本模板、删除小节标题或随意清空内容的 issue,可能会被直接关闭;重复恶意提交者可能会被 block。
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: 您当前的 newapi 版本
|
||||
description: 请填写,例如:`v1.0.0`
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: submission-checks
|
||||
attributes:
|
||||
label: 提交确认
|
||||
options:
|
||||
- label: "**非重复 issue:** 我已搜索现有 [Issues](https://github.com/QuantumNous/new-api/issues?q=is%3Aissue),确认目前没有类似 issue。"
|
||||
required: true
|
||||
- label: "**提交前必读:** 我已完整阅读上方“提交前必读”,并已查看文档 https://docs.newapi.ai/、项目 README 且向 AI 提问,确认这不是使用、配置或接入类问题,且现有版本无法满足需求。"
|
||||
required: true
|
||||
- label: "**模板完整:** 我未删除此模板中的任何引导内容或小节标题,并会按要求完整填写。"
|
||||
required: true
|
||||
- label: "**维护成本:** 我理解项目维护者精力有限,不遵循模板要求的 issue 可能会被无视或直接关闭。"
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: feature-description
|
||||
attributes:
|
||||
label: 功能描述
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: use-case
|
||||
attributes:
|
||||
label: 应用场景
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,54 @@
|
||||
name: Feature Request
|
||||
description: Describe the new feature you would like to add with clear and detailed language
|
||||
labels:
|
||||
- enhancement
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
<!--
|
||||
If you are an AI coding agent: do not fill this GitHub form. Create the issue with the filled body from `.agents/github/ISSUE.md`.
|
||||
-->
|
||||
## Read This First (Do Not Remove This Section)
|
||||
|
||||
- Docs: https://docs.newapi.ai/
|
||||
- Usage questions first: https://deepwiki.com/QuantumNous/new-api
|
||||
- Issues about forwarding behavior after enabling pass-through mode are not accepted; pass-through mode forwards requests directly, so please verify upstream behavior yourself.
|
||||
- Reports about Coding Plan services, reverse-engineered channels, third-party API wrappers, or compatibility issues caused by exposing a Codex endpoint through a reverse proxy as a general-purpose API are not accepted. Protocols or behavior specific to the Codex API should not be treated as standard OpenAI API behavior; confirm such issues with the channel or API provider first.
|
||||
- Warning: issues with this template removed, section headings deleted, or content cleared may be closed directly. Repeated abusive submissions may result in a block.
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Your current newapi version
|
||||
description: "Please fill this in, for example: `v1.0.0`"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: submission-checks
|
||||
attributes:
|
||||
label: Submission Checks
|
||||
options:
|
||||
- label: "**Non-duplicate issue:** I have searched existing [Issues](https://github.com/QuantumNous/new-api/issues?q=is%3Aissue) and confirmed there are no similar issues."
|
||||
required: true
|
||||
- label: "**Read this first:** I have fully read the section above, reviewed the docs at https://docs.newapi.ai/ and the project README, and asked AI first, confirming this is not a usage, configuration, or integration question, and that the current version cannot meet my needs."
|
||||
required: true
|
||||
- label: "**Template intact:** I have not removed any guidance or section headings from this template and will complete it as requested."
|
||||
required: true
|
||||
- label: "**Maintainer time:** I understand that maintainers have limited time and issues that do not follow this template may be ignored or closed directly."
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: feature-description
|
||||
attributes:
|
||||
label: Feature Description
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: use-case
|
||||
attributes:
|
||||
label: Use Case
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,40 @@
|
||||
<!--
|
||||
If you are an AI coding agent (Claude Code, Codex, Cursor, Copilot, OpenCode, Paseo, Grok, or similar): do not fill this human template. Read `.agents/github/PR.md` and use the filled file as the entire PR body.
|
||||
-->
|
||||
# ⚠️ 提交说明 / PR Notice
|
||||
|
||||
English template: `.github/PULL_REQUEST_TEMPLATE/en.md`
|
||||
|
||||
> [!IMPORTANT]
|
||||
>
|
||||
> - 描述可用 AI 辅助。提交前请审阅全文,并**声明对其负责**,避免未经核对的直接粘贴。
|
||||
> - 请按本模板填写后再提交。
|
||||
|
||||
## 🔗 关联任务 / Related Issue
|
||||
- 新功能请填写下方 Issue 编号;若还没有对应 Issue,请先自行创建。功能讨论请放在 Issue 中进行。
|
||||
- 改动较大或方向性变更,请先在关联 Issue 中与维护者达成一致,再提交 PR。
|
||||
- Bug 修复请关联对应 Issue。设计取舍、理解偏差或预期不一致,更适合作为讨论或功能请求。
|
||||
|
||||
- Closes #
|
||||
|
||||
## 🚀 变更类型 / Type of change
|
||||
- [ ] 🐛 Bug 修复 (Bug fix)
|
||||
- [ ] ✨ 新功能 (New feature)
|
||||
- [ ] ⚡ 性能优化 / 重构 (Refactor)
|
||||
- [ ] 📝 文档更新 (Documentation)
|
||||
|
||||
## 📝 变更描述 / Description
|
||||
(简述做了什么、为什么生效。如果难以简述,建议先拆分范围,或在 Issue 中与维护者对齐。)
|
||||
|
||||
## 📸 运行证明 / Proof of Work
|
||||
(请写明如何验证:实际步骤与观察结果。UI 变更请附截图或录屏;Bug 修复请说明复现过程与修复后结果。)
|
||||
|
||||
## ✅ 提交前检查项 / Checklist
|
||||
- [ ] **人工确认:** 无论描述是否由 AI 生成,我已审阅全部内容,并声明对其准确性与完整性负责。
|
||||
- [ ] **非重复提交:** 我已搜索现有的 [Issues](https://github.com/QuantumNous/new-api/issues) 与 [PRs](https://github.com/QuantumNous/new-api/pulls),确认不是重复提交。
|
||||
- [ ] **新功能关联 Issue:** 若此 PR 标记为 `New feature`,我已关联对应 Issue;若尚无 Issue,我已先自行创建。
|
||||
- [ ] **事前沟通:** 若改动较大或涉及方向性变更,已在关联 Issue 中与维护者沟通并达成一致。
|
||||
- [ ] **功能范围:** 本 PR 不是 Coding Plan、逆向渠道、第三方封装接口,也不是对 Codex 渠道类型的改动。
|
||||
- [ ] **范围聚焦:** 本 PR 为一项聚焦改动,未包含无关代码。
|
||||
- [ ] **本地验证:** 已在本地运行并通过测试或手动验证,维护者可以据此复核。
|
||||
- [ ] **安全合规:** 代码中无敏感凭据,且符合项目代码规范。
|
||||
@@ -0,0 +1,40 @@
|
||||
<!--
|
||||
If you are an AI coding agent (Claude Code, Codex, Cursor, Copilot, OpenCode, Paseo, Grok, or similar): do not fill this human template. Read `.agents/github/PR.md` and use the filled file as the entire PR body.
|
||||
-->
|
||||
# PR Notice
|
||||
|
||||
Chinese template: `.github/PULL_REQUEST_TEMPLATE.md`
|
||||
|
||||
> [!IMPORTANT]
|
||||
>
|
||||
> - AI-assisted descriptions are welcome. Please review the full text before submitting and **take responsibility** for it. Avoid pasting unreviewed content.
|
||||
> - Please complete this template before submitting.
|
||||
|
||||
## Related Issue
|
||||
- For new features, please fill in the Issue number below. If none exists yet, please create one first. Please discuss the feature in the Issue rather than using the PR in its place.
|
||||
- For large or directional changes, please reach agreement with maintainers in the linked Issue before opening a PR.
|
||||
- Bug fixes should link a corresponding Issue. Design trade-offs, misunderstandings, or mismatched expectations are a better fit for a discussion or feature request.
|
||||
|
||||
- Closes #
|
||||
|
||||
## Type of change
|
||||
- [ ] Bug fix
|
||||
- [ ] New feature
|
||||
- [ ] Performance / Refactor
|
||||
- [ ] Documentation
|
||||
|
||||
## Description
|
||||
(Briefly describe what changed and why it works. If that is hard to summarize, consider splitting the scope or aligning with maintainers in an Issue first.)
|
||||
|
||||
## Proof of Work
|
||||
(Please describe how this was verified: the steps run and what was observed. For UI changes, please include a screenshot or recording. For bug fixes, please describe the reproduction and the result after the fix.)
|
||||
|
||||
## Checklist
|
||||
- [ ] **Human review:** Whether or not the description was AI-generated, I have reviewed the full content and take responsibility for its accuracy and completeness.
|
||||
- [ ] **Not a duplicate:** I have searched existing [Issues](https://github.com/QuantumNous/new-api/issues) and [PRs](https://github.com/QuantumNous/new-api/pulls) and confirmed this is not a duplicate.
|
||||
- [ ] **Feature issue:** If this PR is a New feature, I have linked a corresponding Issue; if none existed, I created one first.
|
||||
- [ ] **Prior discussion:** If this is a large or directional change, I have discussed it with maintainers in the linked Issue and reached agreement.
|
||||
- [ ] **Scope:** This PR is not a Coding Plan, reverse-engineered channel, third-party API wrapper, or a change to the Codex channel type.
|
||||
- [ ] **Focused change:** This PR is a single focused change and does not include unrelated code.
|
||||
- [ ] **Local verification:** I have run tests or manually verified locally so maintainers can re-check from this evidence.
|
||||
- [ ] **Security:** This change does not include secrets and follows the project's coding guidelines.
|
||||
@@ -0,0 +1,96 @@
|
||||
# Security Policy
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Bulk Reporting Policy:** If you need to submit multiple vulnerability reports in bulk, **you must contact us first** ([support@quantumnous.com](mailto:support@quantumnous.com)) to coordinate the submission process. Uncoordinated bulk submissions have caused significant disruption to our team, and we will take the following actions:
|
||||
>
|
||||
> 1. **All uncoordinated bulk reports will be closed without review.**
|
||||
> 2. **Repeated offenders may be blocked** from further submissions.
|
||||
>
|
||||
> We welcome thorough security research, but please reach out before submitting multiple reports.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
We provide security updates for the following versions:
|
||||
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| Latest | :white_check_mark: |
|
||||
| Older | :x: |
|
||||
|
||||
|
||||
We strongly recommend that users always use the latest version for the best security and features.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
We take security vulnerability reports very seriously. If you discover a security issue, please follow the steps below for responsible disclosure.
|
||||
|
||||
### How to Report
|
||||
|
||||
**Do NOT** report security vulnerabilities in public GitHub Issues.
|
||||
|
||||
To report a security issue, please use the GitHub Security Advisories tab to "[Open a draft security advisory](https://github.com/QuantumNous/new-api/security/advisories/new)". This is the preferred method as it provides a built-in private communication channel.
|
||||
|
||||
Alternatively, you can report via email:
|
||||
|
||||
- **Email:** [support@quantumnous.com](mailto:support@quantumnous.com)
|
||||
- **Subject:** `[SECURITY] Security Vulnerability Report`
|
||||
|
||||
### What to Include
|
||||
|
||||
To help us understand and resolve the issue more quickly, please include the following information in your report:
|
||||
|
||||
1. **Vulnerability Type** - Brief description of the vulnerability (e.g., SQL injection, XSS, authentication bypass, etc.)
|
||||
2. **Affected Component** - Affected file paths, endpoints, or functional modules
|
||||
3. **Reproduction Steps** - Detailed steps to reproduce
|
||||
4. **Impact Assessment** - Potential security impact and severity assessment
|
||||
5. **Proof of Concept** - If possible, provide proof of concept code or screenshots (do not test in production environments)
|
||||
6. **Suggested Fix** - If you have a fix suggestion, please provide it
|
||||
7. **Your Contact Information** - So we can communicate with you
|
||||
|
||||
## Response Process
|
||||
|
||||
1. **Acknowledgment:** We will acknowledge receipt of your report within **48 hours**.
|
||||
2. **Initial Assessment:** We will complete an initial assessment and communicate with you within **7 days**.
|
||||
3. **Fix Development:** Based on the severity of the vulnerability, we will prioritize developing a fix.
|
||||
4. **Security Advisory:** After the fix is released, we will publish a security advisory (if applicable).
|
||||
5. **Credit:** If you wish, we will credit your contribution in the security advisory.
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
When deploying and using New API, we recommend following these security best practices:
|
||||
|
||||
### Deployment Security
|
||||
|
||||
- **Use HTTPS:** Always serve over HTTPS to ensure transport layer security
|
||||
- **Firewall Configuration:** Only open necessary ports and restrict access to management interfaces
|
||||
- **Regular Updates:** Update to the latest version promptly to receive security patches
|
||||
- **Environment Isolation:** Use separate database and Redis instances in production
|
||||
|
||||
### API Key Security
|
||||
|
||||
- **Key Protection:** Do not expose API keys in client-side code or public repositories
|
||||
- **Least Privilege:** Create different API keys for different purposes, following the principle of least privilege
|
||||
- **Regular Rotation:** Rotate API keys regularly
|
||||
- **Monitor Usage:** Monitor API key usage and detect anomalies promptly
|
||||
|
||||
### Database Security
|
||||
|
||||
- **Strong Passwords:** Use strong passwords to protect database access
|
||||
- **Network Isolation:** Database should not be directly exposed to the public internet
|
||||
- **Regular Backups:** Regularly backup the database and verify backup integrity
|
||||
- **Access Control:** Limit database user permissions, following the principle of least privilege
|
||||
|
||||
## Security-Related Configuration
|
||||
|
||||
Please ensure the following security-related environment variables and settings are properly configured:
|
||||
|
||||
- `SESSION_SECRET` - Use a strong random string
|
||||
- `SQL_DSN` - Ensure database connection uses secure configuration
|
||||
- `REDIS_CONN_STRING` - If using Redis, ensure secure connection
|
||||
|
||||
For detailed configuration instructions, please refer to the project documentation.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This project is provided "as is" without any express or implied warranty. Users should assess the security risks of using this software in their environment.
|
||||
@@ -0,0 +1,88 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, closed]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ci-${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
backend:
|
||||
name: Backend vet, build, and test
|
||||
if: github.event.action != 'closed' || github.event.pull_request.merged == true
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
env:
|
||||
GOWORK: 'off'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
repository: ${{ github.event.pull_request.base.repo.full_name }}
|
||||
ref: ${{ github.event.action == 'closed' && github.event.pull_request.base.ref || github.ref }}
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache-dependency-path: |
|
||||
go.sum
|
||||
relaykit/go.sum
|
||||
|
||||
- name: Create frontend embed placeholder
|
||||
run: |
|
||||
mkdir -p web/dist
|
||||
touch web/dist/index.html
|
||||
|
||||
- name: Vet root module
|
||||
run: go vet ./...
|
||||
|
||||
- name: Vet relaykit independently
|
||||
working-directory: relaykit
|
||||
run: go vet ./...
|
||||
|
||||
- name: Build root module
|
||||
run: go build ./...
|
||||
|
||||
- name: Build relaykit independently
|
||||
working-directory: relaykit
|
||||
run: go build ./...
|
||||
|
||||
- name: Test root and relaykit modules
|
||||
run: make test
|
||||
|
||||
frontend:
|
||||
name: Frontend typecheck and test
|
||||
if: github.event.action != 'closed' || github.event.pull_request.merged == true
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
defaults:
|
||||
run:
|
||||
working-directory: web
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
repository: ${{ github.event.pull_request.base.repo.full_name }}
|
||||
ref: ${{ github.event.action == 'closed' && github.event.pull_request.base.ref || github.ref }}
|
||||
|
||||
- name: Set up Bun
|
||||
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
||||
with:
|
||||
bun-version: '1.4.0'
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Typecheck
|
||||
run: bun run typecheck
|
||||
|
||||
- name: Test
|
||||
run: bun run test
|
||||
@@ -0,0 +1,152 @@
|
||||
name: Publish Docker image (Multi-arch)
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
- '!nightly*'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Tag name to build (e.g., v0.10.8-alpha.3)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build_single_arch:
|
||||
name: Build & push (${{ matrix.arch }})
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: amd64
|
||||
platform: linux/amd64
|
||||
runner: ubuntu-latest
|
||||
- arch: arm64
|
||||
platform: linux/arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
runs-on: ${{ matrix.runner }}
|
||||
outputs:
|
||||
tag: ${{ steps.version.outputs.tag }}
|
||||
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Check out
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
fetch-depth: ${{ github.event_name == 'workflow_dispatch' && 0 || 1 }}
|
||||
ref: ${{ github.event.inputs.tag || github.ref }}
|
||||
|
||||
- name: Resolve tag & write VERSION
|
||||
id: version
|
||||
run: |
|
||||
if [ -n "${{ github.event.inputs.tag }}" ]; then
|
||||
TAG="${{ github.event.inputs.tag }}"
|
||||
if ! git rev-parse "refs/tags/$TAG" >/dev/null 2>&1; then
|
||||
echo "::error::Tag '$TAG' does not exist"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
TAG=${GITHUB_REF#refs/tags/}
|
||||
fi
|
||||
echo "TAG=${TAG}" >> $GITHUB_ENV
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
echo "${TAG}" > VERSION
|
||||
echo "Building tag: ${TAG} for ${{ matrix.arch }}"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 # v4.3.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata (labels)
|
||||
id: meta
|
||||
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
|
||||
with:
|
||||
images: calciumion/new-api
|
||||
|
||||
- name: Build & push
|
||||
id: build
|
||||
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
|
||||
with:
|
||||
context: .
|
||||
platforms: ${{ matrix.platform }}
|
||||
push: true
|
||||
tags: |
|
||||
calciumion/new-api:${{ env.TAG }}-${{ matrix.arch }}
|
||||
calciumion/new-api:latest-${{ matrix.arch }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
provenance: mode=max
|
||||
sbom: true
|
||||
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
|
||||
|
||||
- name: Sign image with cosign
|
||||
run: cosign sign --yes calciumion/new-api@${{ steps.build.outputs.digest }}
|
||||
|
||||
- name: Image summary
|
||||
run: |
|
||||
echo "### Docker Image Digest (${{ matrix.arch }})" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
echo "calciumion/new-api:${TAG}-${{ matrix.arch }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "${{ steps.build.outputs.digest }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
create_manifests:
|
||||
name: Create multi-arch manifests
|
||||
needs: [build_single_arch]
|
||||
runs-on: ubuntu-latest
|
||||
if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Set version
|
||||
run: echo "TAG=${{ needs.build_single_arch.outputs.tag }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 # v4.3.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Create & push manifest (version)
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
-t calciumion/new-api:${TAG} \
|
||||
calciumion/new-api:${TAG}-amd64 \
|
||||
calciumion/new-api:${TAG}-arm64
|
||||
|
||||
- name: Create & push manifest (latest)
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
-t calciumion/new-api:latest \
|
||||
calciumion/new-api:latest-amd64 \
|
||||
calciumion/new-api:latest-arm64
|
||||
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@v3
|
||||
|
||||
- name: Sign manifests with cosign
|
||||
run: |
|
||||
cosign sign --yes calciumion/new-api:${TAG}
|
||||
cosign sign --yes calciumion/new-api:latest
|
||||
|
||||
- name: Manifest summary
|
||||
run: |
|
||||
echo "### Multi-arch Manifest" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
docker buildx imagetools inspect calciumion/new-api:${TAG} >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
@@ -0,0 +1,170 @@
|
||||
name: Publish Docker image (manual branch)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch:
|
||||
description: "Branch name to build (e.g. alpha, nightly)"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
name: Prepare Docker tags
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
branch: ${{ steps.version.outputs.branch }}
|
||||
sha: ${{ steps.version.outputs.sha }}
|
||||
tag_prefix: ${{ steps.version.outputs.tag_prefix }}
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Check out branch
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
fetch-depth: 1
|
||||
ref: ${{ inputs.branch }}
|
||||
|
||||
- name: Resolve Docker tags
|
||||
id: version
|
||||
env:
|
||||
BRANCH_NAME: ${{ inputs.branch }}
|
||||
run: |
|
||||
TAG_PREFIX=$(printf '%s' "$BRANCH_NAME" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9_.-]+/-/g; s/^[.-]+//; s/[.-]+$//')
|
||||
TAG_PREFIX=${TAG_PREFIX:0:105}
|
||||
TAG_PREFIX=$(printf '%s' "$TAG_PREFIX" | sed -E 's/[.-]+$//')
|
||||
if [ -z "$TAG_PREFIX" ]; then
|
||||
echo "::error::Branch '$BRANCH_NAME' cannot be converted to a valid Docker tag prefix"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SHA=$(git rev-parse HEAD)
|
||||
SHORT_SHA=$(git rev-parse --short HEAD)
|
||||
VERSION="${TAG_PREFIX}-$(date +'%Y%m%d')-${SHORT_SHA}"
|
||||
|
||||
echo "branch=$BRANCH_NAME" >> "$GITHUB_OUTPUT"
|
||||
echo "sha=$SHA" >> "$GITHUB_OUTPUT"
|
||||
echo "tag_prefix=$TAG_PREFIX" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "Prepared Docker tags for $BRANCH_NAME at $SHORT_SHA"
|
||||
|
||||
build_single_arch:
|
||||
name: Build & push (${{ matrix.arch }}) [native]
|
||||
needs: [prepare]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: amd64
|
||||
platform: linux/amd64
|
||||
runner: ubuntu-latest
|
||||
- arch: arm64
|
||||
platform: linux/arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
runs-on: ${{ matrix.runner }}
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Check out branch
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
fetch-depth: 1
|
||||
ref: ${{ needs.prepare.outputs.sha }}
|
||||
|
||||
- name: Write VERSION
|
||||
run: |
|
||||
echo "${{ needs.prepare.outputs.version }}" > VERSION
|
||||
echo "Publishing version: ${{ needs.prepare.outputs.version }} for ${{ matrix.arch }}"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 # v4.3.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata (labels)
|
||||
id: meta
|
||||
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
|
||||
with:
|
||||
images: |
|
||||
calciumion/new-api
|
||||
|
||||
- name: Build & push single-arch
|
||||
id: build
|
||||
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
|
||||
with:
|
||||
context: .
|
||||
platforms: ${{ matrix.platform }}
|
||||
push: true
|
||||
tags: |
|
||||
calciumion/new-api:${{ needs.prepare.outputs.tag_prefix }}-${{ matrix.arch }}
|
||||
calciumion/new-api:${{ needs.prepare.outputs.version }}-${{ matrix.arch }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
provenance: mode=max
|
||||
sbom: true
|
||||
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
|
||||
|
||||
- name: Sign image with cosign
|
||||
run: cosign sign --yes calciumion/new-api@${{ steps.build.outputs.digest }}
|
||||
|
||||
- name: Output digest
|
||||
run: |
|
||||
echo "### Docker Image Digest (${{ matrix.arch }})" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
echo "calciumion/new-api:${{ needs.prepare.outputs.tag_prefix }}-${{ matrix.arch }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "calciumion/new-api:${{ needs.prepare.outputs.version }}-${{ matrix.arch }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "${{ steps.build.outputs.digest }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
create_manifests:
|
||||
name: Create multi-arch manifests (Docker Hub)
|
||||
needs: [prepare, build_single_arch]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 # v4.3.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Create & push manifest (Docker Hub - branch)
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
-t calciumion/new-api:${{ needs.prepare.outputs.tag_prefix }} \
|
||||
calciumion/new-api:${{ needs.prepare.outputs.tag_prefix }}-amd64 \
|
||||
calciumion/new-api:${{ needs.prepare.outputs.tag_prefix }}-arm64
|
||||
|
||||
- name: Create & push manifest (Docker Hub - versioned)
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
-t calciumion/new-api:${{ needs.prepare.outputs.version }} \
|
||||
calciumion/new-api:${{ needs.prepare.outputs.version }}-amd64 \
|
||||
calciumion/new-api:${{ needs.prepare.outputs.version }}-arm64
|
||||
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
|
||||
|
||||
- name: Sign manifests with cosign
|
||||
run: |
|
||||
cosign sign --yes calciumion/new-api:${{ needs.prepare.outputs.tag_prefix }}
|
||||
cosign sign --yes calciumion/new-api:${{ needs.prepare.outputs.version }}
|
||||
|
||||
- name: Output manifest digest
|
||||
run: |
|
||||
echo "### Multi-arch Manifest Digests" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
docker buildx imagetools inspect calciumion/new-api:${{ needs.prepare.outputs.tag_prefix }} >> $GITHUB_STEP_SUMMARY
|
||||
echo "---" >> $GITHUB_STEP_SUMMARY
|
||||
docker buildx imagetools inspect calciumion/new-api:${{ needs.prepare.outputs.version }} >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
@@ -0,0 +1,141 @@
|
||||
name: Build Electron App
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*' # Triggers on version tags like v1.0.0
|
||||
- '!*-*' # Ignore pre-release tags like v1.0.0-beta
|
||||
- '!*-alpha*' # Ignore alpha tags like v1.0.0-alpha
|
||||
workflow_dispatch: # Allows manual triggering
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
# os: [macos-latest, windows-latest]
|
||||
os: [windows-latest]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
||||
with:
|
||||
bun-version: '1.4.0'
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
|
||||
with:
|
||||
go-version: '>=1.25.1'
|
||||
|
||||
- name: Build frontend
|
||||
env:
|
||||
CI: ""
|
||||
NODE_OPTIONS: "--max-old-space-size=4096"
|
||||
run: |
|
||||
cd web
|
||||
bun install --frozen-lockfile
|
||||
DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$(git describe --tags) bun run build
|
||||
cd ..
|
||||
|
||||
# - name: Build Go binary (macos/Linux)
|
||||
# if: runner.os != 'Windows'
|
||||
# run: |
|
||||
# go mod download
|
||||
# go build -ldflags "-s -w -X 'new-api/common.Version=$(git describe --tags)' -extldflags '-static'" -o new-api
|
||||
|
||||
- name: Build Go binary (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
go mod download
|
||||
go build -ldflags "-s -w -X 'new-api/common.Version=$(git describe --tags)'" -o new-api.exe
|
||||
|
||||
- name: Update Electron version
|
||||
run: |
|
||||
cd electron
|
||||
VERSION=$(git describe --tags)
|
||||
VERSION=${VERSION#v} # Remove 'v' prefix if present
|
||||
# Convert to valid semver: take first 3 components and convert rest to prerelease format
|
||||
# e.g., 0.9.3-patch.1 -> 0.9.3-patch.1
|
||||
if [[ $VERSION =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)(.*)$ ]]; then
|
||||
MAJOR=${BASH_REMATCH[1]}
|
||||
MINOR=${BASH_REMATCH[2]}
|
||||
PATCH=${BASH_REMATCH[3]}
|
||||
REST=${BASH_REMATCH[4]}
|
||||
|
||||
VERSION="$MAJOR.$MINOR.$PATCH"
|
||||
|
||||
# If there's extra content, append it without adding -dev
|
||||
if [[ -n "$REST" ]]; then
|
||||
VERSION="$VERSION$REST"
|
||||
fi
|
||||
fi
|
||||
npm version $VERSION --no-git-tag-version --allow-same-version
|
||||
|
||||
- name: Install Electron dependencies
|
||||
run: |
|
||||
cd electron
|
||||
npm install
|
||||
|
||||
# - name: Build Electron app (macOS)
|
||||
# if: runner.os == 'macOS'
|
||||
# run: |
|
||||
# cd electron
|
||||
# npm run build:mac
|
||||
# env:
|
||||
# CSC_IDENTITY_AUTO_DISCOVERY: false # Skip code signing
|
||||
|
||||
- name: Build Electron app (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
cd electron
|
||||
npm run build:win
|
||||
|
||||
# - name: Upload artifacts (macOS)
|
||||
# if: runner.os == 'macOS'
|
||||
# uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
# with:
|
||||
# name: macos-build
|
||||
# path: |
|
||||
# electron/dist/*.dmg
|
||||
# electron/dist/*.zip
|
||||
|
||||
- name: Upload artifacts (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: windows-build
|
||||
path: |
|
||||
electron/dist/*.exe
|
||||
|
||||
release:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
|
||||
- name: Upload to Release
|
||||
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
|
||||
with:
|
||||
files: |
|
||||
windows-build/*
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,168 @@
|
||||
name: Release (Linux, macOS, Windows)
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
name:
|
||||
description: 'reason'
|
||||
required: false
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
- '!*-alpha*'
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
name: Linux Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Determine Version
|
||||
run: |
|
||||
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
|
||||
VERSION=${GITHUB_REF#refs/tags/}
|
||||
else
|
||||
VERSION=$(git describe --tags --match 'v[0-9]*')
|
||||
fi
|
||||
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
||||
with:
|
||||
bun-version: '1.4.0'
|
||||
- name: Build Frontend
|
||||
env:
|
||||
CI: ""
|
||||
run: |
|
||||
cd web
|
||||
bun install --frozen-lockfile
|
||||
DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$VERSION bun run build
|
||||
cd ..
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
|
||||
with:
|
||||
go-version: '>=1.25.1'
|
||||
- name: Build Backend (amd64)
|
||||
run: |
|
||||
go mod download
|
||||
go build -ldflags "-s -w -X 'new-api/common.Version=$VERSION' -extldflags '-static'" -o new-api-$VERSION
|
||||
- name: Build Backend (arm64)
|
||||
run: |
|
||||
sudo apt-get update
|
||||
DEBIAN_FRONTEND=noninteractive sudo apt-get install -y gcc-aarch64-linux-gnu
|
||||
CC=aarch64-linux-gnu-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -X 'new-api/common.Version=$VERSION' -extldflags '-static'" -o new-api-arm64-$VERSION
|
||||
- name: Generate checksums
|
||||
run: sha256sum new-api-* > checksums-linux.txt
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
files: |
|
||||
new-api-*
|
||||
checksums-linux.txt
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
macos:
|
||||
name: macOS Release
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Determine Version
|
||||
run: |
|
||||
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
|
||||
VERSION=${GITHUB_REF#refs/tags/}
|
||||
else
|
||||
VERSION=$(git describe --tags --match 'v[0-9]*')
|
||||
fi
|
||||
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
||||
with:
|
||||
bun-version: '1.4.0'
|
||||
- name: Build Frontend
|
||||
env:
|
||||
CI: ""
|
||||
NODE_OPTIONS: "--max-old-space-size=4096"
|
||||
run: |
|
||||
cd web
|
||||
bun install --frozen-lockfile
|
||||
DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$VERSION bun run build
|
||||
cd ..
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
|
||||
with:
|
||||
go-version: '>=1.25.1'
|
||||
- name: Build Backend
|
||||
run: |
|
||||
go mod download
|
||||
go build -ldflags "-X 'new-api/common.Version=$VERSION'" -o new-api-macos-$VERSION
|
||||
- name: Generate checksums
|
||||
run: shasum -a 256 new-api-macos-* > checksums-macos.txt
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
files: |
|
||||
new-api-macos-*
|
||||
checksums-macos.txt
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
windows:
|
||||
name: Windows Release
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Determine Version
|
||||
run: |
|
||||
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
|
||||
VERSION=${GITHUB_REF#refs/tags/}
|
||||
else
|
||||
VERSION=$(git describe --tags --match 'v[0-9]*')
|
||||
fi
|
||||
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
||||
with:
|
||||
bun-version: '1.4.0'
|
||||
- name: Build Frontend
|
||||
env:
|
||||
CI: ""
|
||||
run: |
|
||||
cd web
|
||||
bun install --frozen-lockfile
|
||||
DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$VERSION bun run build
|
||||
cd ..
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
|
||||
with:
|
||||
go-version: '>=1.25.1'
|
||||
- name: Build Backend
|
||||
run: |
|
||||
go mod download
|
||||
go build -ldflags "-s -w -X 'new-api/common.Version=$VERSION'" -o new-api-$VERSION.exe
|
||||
- name: Generate checksums
|
||||
run: sha256sum new-api-*.exe > checksums-windows.txt
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
files: |
|
||||
new-api-*.exe
|
||||
checksums-windows.txt
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,250 @@
|
||||
name: Sync Release to GitCode
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag_name:
|
||||
description: GitHub release tag to sync
|
||||
required: true
|
||||
type: string
|
||||
sync_files:
|
||||
description: Sync GitHub release files to GitCode
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
concurrency:
|
||||
group: gitcode-release-${{ inputs.tag_name }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
prepare-release:
|
||||
name: Create or update GitCode release
|
||||
if: ${{ vars.GITCODE_REPOSITORY != '' }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
outputs:
|
||||
release_tag: ${{ steps.release.outputs.tag }}
|
||||
release_body: ${{ steps.release.outputs.body }}
|
||||
release_prerelease: ${{ steps.release.outputs.prerelease }}
|
||||
release_asset_matrix: ${{ steps.assets.outputs.matrix }}
|
||||
has_release_assets: ${{ steps.assets.outputs.has_assets }}
|
||||
steps:
|
||||
- name: Create or update GitCode release
|
||||
id: release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITCODE_REPOSITORY: ${{ vars.GITCODE_REPOSITORY }}
|
||||
GITCODE_TOKEN: ${{ secrets.GITCODE_TOKEN }}
|
||||
RELEASE_TAG: ${{ inputs.tag_name }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
release_json="$(
|
||||
gh release view "$RELEASE_TAG" \
|
||||
--repo "$GITHUB_REPOSITORY" \
|
||||
--json body,isPrerelease
|
||||
)"
|
||||
release_body="$(jq -r '.body // ""' <<< "$release_json" | sed "s/'/’/g")"
|
||||
release_prerelease="$(jq -r '.isPrerelease' <<< "$release_json")"
|
||||
if [[ "$release_prerelease" == "true" ]]; then
|
||||
release_status=pre
|
||||
else
|
||||
release_status=latest
|
||||
fi
|
||||
|
||||
gitcode_release_json="$(mktemp)"
|
||||
gitcode_release_status="$(
|
||||
curl -L -sS -o "$gitcode_release_json" -w "%{http_code}" \
|
||||
-H "PRIVATE-TOKEN: $GITCODE_TOKEN" \
|
||||
-H "Accept: application/json" \
|
||||
"https://api.gitcode.com/api/v5/repos/$GITCODE_REPOSITORY/releases/tags/$RELEASE_TAG"
|
||||
)"
|
||||
|
||||
request_json="$(mktemp)"
|
||||
case "$gitcode_release_status" in
|
||||
200)
|
||||
request_method=PATCH
|
||||
request_url="https://api.gitcode.com/api/v5/repos/$GITCODE_REPOSITORY/releases/$RELEASE_TAG"
|
||||
request_action=update
|
||||
success_action=updated
|
||||
jq -n \
|
||||
--arg tag_name "$RELEASE_TAG" \
|
||||
--arg name "$RELEASE_TAG" \
|
||||
--arg body "$release_body" \
|
||||
--arg release_status "$release_status" \
|
||||
'{
|
||||
tag_name: $tag_name,
|
||||
name: $name,
|
||||
body: $body,
|
||||
release_status: $release_status
|
||||
}' > "$request_json"
|
||||
;;
|
||||
404)
|
||||
if ! git ls-remote --exit-code --tags \
|
||||
"https://gitcode.com/$GITCODE_REPOSITORY.git" \
|
||||
"refs/tags/$RELEASE_TAG" > /dev/null; then
|
||||
echo "::error::Tag $RELEASE_TAG has not been mirrored to GitCode yet. Retry this workflow after the tag appears on GitCode."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
request_method=POST
|
||||
request_url="https://api.gitcode.com/api/v5/repos/$GITCODE_REPOSITORY/releases"
|
||||
request_action=create
|
||||
success_action=created
|
||||
jq -n \
|
||||
--arg tag_name "$RELEASE_TAG" \
|
||||
--arg name "$RELEASE_TAG" \
|
||||
--arg body "$release_body" \
|
||||
--arg release_status "$release_status" \
|
||||
'{
|
||||
tag_name: $tag_name,
|
||||
name: $name,
|
||||
body: $body,
|
||||
release_status: $release_status
|
||||
}' > "$request_json"
|
||||
;;
|
||||
*)
|
||||
echo "::error::Failed to inspect GitCode release. Response code: $gitcode_release_status"
|
||||
cat "$gitcode_release_json"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
gitcode_response_json="$(mktemp)"
|
||||
request_status="$(
|
||||
curl -L -sS -o "$gitcode_response_json" -w "%{http_code}" \
|
||||
-X "$request_method" \
|
||||
-H "PRIVATE-TOKEN: $GITCODE_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
--data-binary "@$request_json" \
|
||||
"$request_url"
|
||||
)"
|
||||
if [[ "$request_status" != "200" ]]; then
|
||||
echo "::error::Failed to $request_action GitCode release. Response code: $request_status"
|
||||
cat "$gitcode_response_json"
|
||||
exit 1
|
||||
fi
|
||||
echo "GitCode release $success_action successfully"
|
||||
|
||||
delimiter="release-body-$(openssl rand -hex 16)"
|
||||
{
|
||||
echo "tag=$RELEASE_TAG"
|
||||
echo "body<<$delimiter"
|
||||
echo "$release_body"
|
||||
echo "$delimiter"
|
||||
echo "prerelease=$release_prerelease"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Download GitHub release assets
|
||||
if: ${{ inputs.sync_files }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RELEASE_TAG: ${{ inputs.tag_name }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
mkdir release-assets
|
||||
gh release download "$RELEASE_TAG" \
|
||||
--repo "$GITHUB_REPOSITORY" \
|
||||
--dir release-assets
|
||||
|
||||
if ! find release-assets -maxdepth 1 -type f -print -quit | grep -q .; then
|
||||
echo "::error::GitHub release has no downloadable assets"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while IFS= read -r -d '' file; do
|
||||
directory="$(dirname "$file")"
|
||||
filename="$(basename "$file")"
|
||||
safe_filename="$(sed 's/[^A-Za-z0-9._+-]/-/g' <<< "$filename")"
|
||||
if [[ "$filename" != "$safe_filename" ]]; then
|
||||
if [[ -e "$directory/$safe_filename" ]]; then
|
||||
echo "::error::Asset filename collision after normalization: $safe_filename"
|
||||
exit 1
|
||||
fi
|
||||
mv -- "$file" "$directory/$safe_filename"
|
||||
fi
|
||||
done < <(find release-assets -maxdepth 1 -type f -print0)
|
||||
|
||||
find release-assets -maxdepth 1 -type f -print | sort
|
||||
|
||||
- name: Prepare GitCode release assets
|
||||
id: assets
|
||||
if: ${{ inputs.sync_files }}
|
||||
env:
|
||||
GITCODE_REPOSITORY: ${{ vars.GITCODE_REPOSITORY }}
|
||||
GITCODE_TOKEN: ${{ secrets.GITCODE_TOKEN }}
|
||||
RELEASE_TAG: ${{ inputs.tag_name }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
local_assets="$(
|
||||
find release-assets -maxdepth 1 -type f -printf '%s\t%f\n' \
|
||||
| sort -n -k1,1 \
|
||||
| cut -f2- \
|
||||
| jq -Rsc 'split("\n") | map(select(length > 0))'
|
||||
)"
|
||||
|
||||
gitcode_release_json="$(mktemp)"
|
||||
gitcode_release_status="$(
|
||||
curl -L -sS -o "$gitcode_release_json" -w "%{http_code}" \
|
||||
-H "PRIVATE-TOKEN: $GITCODE_TOKEN" \
|
||||
-H "Accept: application/json" \
|
||||
"https://api.gitcode.com/api/v5/repos/$GITCODE_REPOSITORY/releases/tags/$RELEASE_TAG"
|
||||
)"
|
||||
if [[ "$gitcode_release_status" != "200" ]]; then
|
||||
echo "::error::Failed to inspect GitCode release assets. Response code: $gitcode_release_status"
|
||||
cat "$gitcode_release_json"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
existing_assets="$(jq -c '[.assets[]?.name]' "$gitcode_release_json")"
|
||||
missing_assets="$(
|
||||
jq -cn \
|
||||
--argjson local_assets "$local_assets" \
|
||||
--argjson existing_assets "$existing_assets" \
|
||||
'$local_assets - $existing_assets'
|
||||
)"
|
||||
jq -rn \
|
||||
--argjson local_assets "$local_assets" \
|
||||
--argjson missing_assets "$missing_assets" \
|
||||
'$local_assets - $missing_assets | .[] | "Skipping existing GitCode asset: \(.)"'
|
||||
|
||||
echo "matrix=$missing_assets" >> "$GITHUB_OUTPUT"
|
||||
echo "has_assets=$(jq -r 'length > 0' <<< "$missing_assets")" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Upload release assets for GitCode
|
||||
if: ${{ inputs.sync_files && steps.assets.outputs.has_assets == 'true' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: gitcode-release-assets
|
||||
path: release-assets/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
gitcode-release-assets:
|
||||
name: Publish GitCode asset (${{ matrix.file_name }})
|
||||
needs: prepare-release
|
||||
if: ${{ inputs.sync_files && needs.prepare-release.result == 'success' && needs.prepare-release.outputs.has_release_assets == 'true' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 4
|
||||
matrix:
|
||||
file_name: ${{ fromJSON(needs.prepare-release.outputs.release_asset_matrix) }}
|
||||
uses: nvdacn/sync_to_gitcode/.github/workflows/CreateReleaseOnGitCode.yaml@18b70112d0e62260bc54085028e5510bbc6323b2
|
||||
with:
|
||||
artifact_name: gitcode-release-assets
|
||||
gitcode_repository: ${{ vars.GITCODE_REPOSITORY }}
|
||||
default_branch: main
|
||||
tag_name: ${{ needs.prepare-release.outputs.release_tag }}
|
||||
body: ${{ needs.prepare-release.outputs.release_body }}
|
||||
prerelease: ${{ needs.prepare-release.outputs.release_prerelease == 'true' }}
|
||||
file_name: ${{ matrix.file_name }}
|
||||
secrets:
|
||||
GITCODE_TOKEN: ${{ secrets.GITCODE_TOKEN }}
|
||||
Reference in new issue
Block a user