Skip to content

Upload Action

Add the action to a workflow step after your build produces one or more .jar or .zip artifacts. The action uploads those files to Guizhan Resources and creates a new project version through the version creation endpoint.

Minimal example using a local file:

- uses: ybw0014/guizhan-resources-action@v0
with:
token: ${{ secrets.GUIZHAN_TOKEN }}
project: my-project
channel: releases
files: build/libs/*.jar

The action calls version creation endpoint on your behalf. Your token must include the project:version:create scope. Organization-owned projects also require the project:version:create organization member permission.

Create a token in your Guizhan Resources account settings and store it as a repository secret (for example, GUIZHAN_TOKEN). The action automatically masks the token in logs.

uses: ybw0014/guizhan-resources-action@v0
Inputs
domain
Default:`https://resources.guizhanss.com/api`

API base URL. A bare host such as resources.guizhanss.com is normalized to https://resources.guizhanss.com/api. Trailing slashes are removed.

tokenRequired

Access token with project:version:create scope.

projectRequired

Project ID or slug.

channelRequired

Channel ID or slug.

filesRequired
Default:none

Newline or comma-separated local paths or glob patterns. At least one of files or artifact-names is required.

artifact-namesRequired
Default:none

Newline or comma-separated GitHub Actions artifact names from the current workflow run. At least one of files or artifact-names is required.

primary-file
Default:none

Basename of the file that should be treated as the primary file. Must match one of the resolved files.

version
Default:`GITHUB_REF_NAME`

Version string. When omitted, the action derives it from GITHUB_REF_NAME and strips one leading v.

name
Default:resolved `version`

Display name for the version.

changelog
Default:omit

Changelog in Markdown.

changelog-file
Default:omit

Path to a UTF-8 file containing the changelog. Leading and trailing whitespace is trimmed. Mutually exclusive with changelog; setting both fails the action.

minecraft-versions
Default:auto/omit

Comma or newline-separated Minecraft versions. Overrides auto-detection.

platforms
Default:auto/omit

Comma or newline-separated platform IDs. Overrides auto-detection.

dependencies
Default:omit

JSON string matching the API dependency format. Fails on invalid JSON. See Dependencies format.

auto-detect-minecraft
Default:`true`

Infer Minecraft versions from resolved file basenames when explicit input is omitted.

auto-detect-platform
Default:`true`

Infer platforms from JAR descriptors or basenames when explicit input is omitted.

retry-attempts
Default:`2`

Total number of upload attempts (including the first) for transient failures (network errors and HTTP 5xx). Must be an integer >= 1.

retry-delay
Default:`1000`

Base delay in milliseconds between retries, scaled by attempt number. Must be an integer >= 0.

fail-mode
Default:`fail`

Behavior when a matched file cannot be parsed or yields no detected metadata: fail errors out, warn uploads it without detected metadata, skip excludes it from the upload.

Outputs
version-id

ID of the created version.

version-url

Direct URL to the created version page.

uploaded-files

Comma-separated list of uploaded file basenames in final order.

api-code

Normalized result code. 0 means success, including a verified idempotent replay of an earlier attempt; otherwise the API error code.

The dependencies input accepts a JSON array of objects. Each object has a type and exactly one identifier:

FieldTypeDescription
typerequired | optional | incompatible | embeddedRelationship to this version.
version_id8-character stringLinks to a specific version on Guizhan Resources.
project_id8-character stringLinks to a project (any compatible version).
name1–64 visible charactersExternal dependency display name. May be paired with url.
urlHTTP(S) URLOptional homepage or download page for external dependencies.

Rules:

  • Provide exactly one of version_id, project_id, or name per entry — more than one or none is rejected.
  • url is only meaningful alongside name.
  • Duplicate identifiers are rejected.
[
{ "type": "required", "version_id": "vers1234" },
{ "type": "optional", "project_id": "proj1234" },
{ "type": "embedded", "name": "Vault", "url": "https://example.com/vault" }
]

In a workflow file, pass it as a single-line JSON string:

- uses: ybw0014/guizhan-resources-action@v0
with:
dependencies: '[{"type":"required","version_id":"vers1234"}]'

Provide files as paths or glob patterns relative to the repository root. The action resolves globs, rejects directories, and validates file basenames and extensions locally. The API validates file-size and file-count limits.

- uses: ybw0014/guizhan-resources-action@v0
with:
token: ${{ secrets.GUIZHAN_TOKEN }}
project: my-project
channel: releases
files: |
build/libs/plugin.jar
build/distributions/docs.zip
primary-file: plugin.jar
version: ${{ github.ref_name }}
changelog: ${{ github.event.release.body }}

If your build step uploads artifacts with actions/upload-artifact, you can reference those artifact names instead of local paths. The action downloads artifacts from the current workflow run into a temporary directory and treats the contained files as upload sources.

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./gradlew build
- uses: actions/upload-artifact@v4
with:
name: plugin-artifact
path: build/libs/*.jar
upload:
needs: build
runs-on: ubuntu-latest
steps:
- uses: ybw0014/guizhan-resources-action@v0
with:
token: ${{ secrets.GUIZHAN_TOKEN }}
project: my-project
channel: releases
artifact-names: plugin-artifact

You can combine files and artifact-names in the same step. Duplicate basenames across sources are rejected before upload.

The first entry in data.files becomes the primary file for the version. This is the file users receive when they click a generic download link. By default, files are sorted by basename then absolute path, so the order is deterministic.

If you want a specific file to be primary, set primary-file to its basename. The action moves that file to the first position in the upload list. primary-file must exactly match one of the resolved basenames.

When minecraft-versions or platforms are not provided explicitly, the action can infer them from the resolved files.

  • Minecraft versions: Scans file basenames for release patterns such as 1.20.4, 1.21, and year-based patterns such as 26.1, 27.10.2. Deduplicates matches and includes them when non-empty.
  • Platforms: Inspects .jar files for paper-plugin.yml (Paper), plugin.yml (Bukkit), and checks basenames for folia, paper, or spigot. Deduplicates matches and includes them when non-empty.

Explicit inputs always override auto-detection. If detection finds nothing, the optional fields are omitted and the API falls back to the channel defaults.

When a matched file cannot be parsed (for example, a non-ZIP archive) or yields no detected metadata, fail-mode decides what happens: fail (default) fails the action, warn uploads the file without detected metadata, and skip silently excludes it from the upload. When explicit minecraft-versions and platforms fully cover auto-detection, files are not parsed at all.

Glob patterns and artifact downloads skip unrelated sidecar files (.sha1, .sha256, .md5, .md, .txt, .json checksums and notes). Files listed as literal paths are always uploaded after validation. The same path matched by multiple patterns uploads only once.

Transient failures (network errors, response-body read failures, and HTTP 5xx) are retried up to retry-attempts total attempts with linear backoff (retry-delay scaled by attempt number plus small jitter). Each HTTP request has its own 10-minute timeout. Validation and authentication errors are not retried.

If the API responds with code 5301 (version already exists) — for example after an earlier attempt succeeded but its response was lost — the action fetches the existing version and compares channel (slug case-insensitively), name, changelog, Minecraft versions, platforms, dependencies, and every file’s name, size, SHA-256, and primary flag. Only an exact match is treated as an idempotent success (api-code 0); any mismatch fails the action. Files excluded by fail-mode: skip are also excluded from this comparison.

ErrorCauseResolution
400Validation failure. Common causes include invalid data JSON, missing required fields, unsupported file types, file count over the limit, or individual files exceeding the size limit.Check that all required inputs are set, files are .jar or .zip, and file sizes are within limits. Verify dependencies is valid JSON if provided.
401Token is missing, expired, or invalid.Confirm the token is stored correctly and has not expired.
403Token lacks the project:version:create scope, or the project is organization-owned and your account lacks the organization member permission.Create a new token with the required scope, or ask the organization owner to grant the permission.
409A version with the same identifier already exists for this project and channel. If it was created by an earlier attempt of this same request, the action verifies it and treats it as success.Change the version input or delete the existing version first.

For transient network errors or HTTP 502/503/504, the action retries up to retry-attempts times (default 2 total attempts) with linear backoff based on retry-delay. Validation and authentication errors are not retried.