Compare commits

..
Author SHA1 Message Date
silverwind 461f40605d ci(snap): build snaps natively instead of on launchpad
Replace `snapcraft remote-build` (Launchpad) with a local `action-build`
on native amd64 + arm64 GitHub-hosted runners, publishing each arch with
`action-publish`. remote-build force-pushes Gitea's full history to a
fresh Launchpad repo every run and races Launchpad's ref indexing within
a fixed retry window, which is unreliable at Gitea's repo size; Canonical
also does not support remote-build in CI.

Drops the LAUNCHPAD_CREDENTIALS secret; publishing keeps using the
existing SNAPCRAFT_STORE_CREDENTIALS. Adds a concurrency group matching
release-nightly.yml so a burst of pushes collapses to the latest commit.

Assisted-by: Claude:Opus-4.8
2026-07-02 16:16:23 +02:00
silverwindandGitHub c6184ed184 chore(snap): drop armhf build (#38311)
Launchpad no longer builds `core24` snaps for `armhf`. Since `snapcraft
remote-build` submits a single request for all platforms, the `armhf`
rejection fails with `snapcraft internal error: BadRequest()` and takes
the `amd64` and `arm64` builds down with it, so nothing gets published.

Dropping 32-bit ARM from `snap/snapcraft.yaml` and the workflow's
`--build-for` restores nightly snap publishing for the remaining
architectures.
2026-07-02 13:55:45 +02:00
8909958055 fix(actions): prevent chevron overlap with log text when timestamps are enabled (#38227)
### Description
This PR resolves a UI alignment bug in the Gitea Actions log viewer
where the expand/collapse disclosure chevron overlaps with the log text
(specifically the timestamp) when timestamps are enabled.

### Cause
When log timestamps are enabled, the timestamp element
(`.log-time-stamp`) is rendered as the first element next to the line
number. Because it only had a default `10px` left margin, it positioned
itself exactly where the group's expand/collapse chevron is located,
causing them to overlap.

### Solution
Updated the CSS styles in `web_src/js/components/ActionRunJobView.vue`
to dynamically apply the `21px` margin to whichever element is the first
visible element after the line number:
- If the timestamp is visible, it gets the `21px` margin to clear the
chevron, and the subsequent log message gets a `10px` margin.
- If the timestamp is hidden, the log message receives the `21px`
margin.

### Before / After
**Before:**
<img width="853" height="348" alt="actions_log_before"
src="https://github.com/user-attachments/assets/d09a752e-18cb-4fe3-b749-4979cbe45240"
/>


**After:**
<img width="862" height="511" alt="actions_log_after"
src="https://github.com/user-attachments/assets/63063f05-8cd6-4986-a993-ed12f28625c8"
/>

Fixes #38222.

---------

Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: silverwind <me@silverwind.io>
2026-07-02 05:20:25 +00:00
638e4bce09 chore: upgrade go-swagger to v0.35.0 and enforce zero swagger warnings (#38299)
Updates `go-swagger` to v0.35.0 and makes swagger generation and
validation warning-free, with the build now failing on any warning
(`go-swagger` itself exits `0` on warnings).

- Generation passes `--enable-allof-compounding` (keeps `$ref` fields
bare, no spec change) and `--skip-enum-desc` (drops the enum description
that duplicates `x-go-enum-desc` and was the only source of `allOf`
noise in the OpenAPI 3.0 output).
- Fixed warnings at the source: dropped `swagger:strfmt` where it
conflicts with `required: true` (`required` kept, `time.Time` still maps
to `date-time`), fixed a malformed `units_map` example, moved the
`parameterBodies` injection hack to `swagger:parameters`, and removed
unused responses.

Fixes: https://github.com/go-gitea/gitea/issues/12508

---------

Co-authored-by: bircni <bircni@icloud.com>
2026-07-01 21:07:34 +00:00
puni9869andGitHub a031454586 fix: Improve since/until when counting commits for X-Total-Count (#38243)
Follow up for https://github.com/go-gitea/gitea/pull/38204.

---------

Signed-off-by: puni9869 <80308335+puni9869@users.noreply.github.com>
2026-07-01 20:43:46 +00:00
c52a07dcfe chore: remove eslint-plugin-array-func (#38294)
The rules from `eslint-plugin-array-func` are redundant with
`eslint-plugin-unicorn`:

- `from-map` → `unicorn/prefer-array-from-map`
- `no-unnecessary-this-arg` → `unicorn/no-array-method-this-argument`
- `prefer-flat` / `prefer-flat-map` → `unicorn/prefer-array-flat` /
`unicorn/prefer-array-flat-map` (already disabled here)

The two remaining rules (`avoid-reverse`, `prefer-array-from`) are niche
and not worth carrying an extra dependency for.

Co-authored-by: bircni <bircni@icloud.com>
2026-07-01 20:16:42 +00:00
bircniandGitHub b6ef881a9f docs: Welcome Zettat to TOC (#38303) 2026-07-01 20:07:44 +00:00
Kausthubh J RaoandGitHub 6240d8bf89 fix(workflows): branch protection status checks fail when workflow uses on: paths filter (#38237) 2026-07-01 21:47:47 +02:00
silverwindandGitHub 9cb2719fab chore: update node.js to v26 (#38285)
- bump ci, flake and `@types/node` to node 26
- regenerate flake.lock which is needed for that package
- refactor workflow to use shared composite action
2026-07-01 16:28:36 +02:00
silverwindandGitHub e8654c7e06 refactor: replace vue-bar-graph dependency with inlined SVG chart (#38292)
Inlines the small SVG bar graph into `RepoActivityTopAuthors.vue` (its
only consumer) and drops the `vue-bar-graph` npm dependency.

- Bars render at static height (dropped the grow animation).
- Theme-aware axis color instead of a hardcoded `#555555`.
- Removed the dangling `role="img"`/`aria-labelledby` on the `<svg>`.
- Reserve the chart height so the page does not shift when the component
mounts.

<img width="416" height="110" alt="Screenshot 2026-07-01 at 11 15 25"
src="https://github.com/user-attachments/assets/b2db4d0c-20f1-4345-9951-32a908abfaba"
/>
<img width="419" height="110" alt="Screenshot 2026-07-01 at 11 15 35"
src="https://github.com/user-attachments/assets/853305a5-575f-4a26-ba3b-12fc51081324"
/>

fyi @lafriks

---------

Signed-off-by: silverwind <me@silverwind.io>
2026-07-01 11:17:23 +00:00
67a6bd7fc0 feat(auth): add disable-2fa command (#38275)
This PR adds the `gitea admin user disable-2fa` command to disable 2FA
for a user

When the only admin in the instance loses their 2FA credentials, this
command can be used to disable 2FA, allowing them to log in and reset
it.

---------

Co-authored-by: Giteabot <teabot@gitea.io>
2026-07-01 12:33:16 +02:00
77e221ffaf fix(oauth2): persist linkAccountData during auto-link 2FA flow (#38274)
Fixes HTTP 500 when OIDC auto account linking (`ACCOUNT_LINKING=auto`)
requires local 2FA. `oauth2LinkAccount` set `linkAccount` in the session
before redirecting to 2FA but did not persist `linkAccountData`, so
`TwoFactorPost` failed with `not in LinkAccount session`. The manual
linking flow already stored both, this aligns auto-link with that
behavior.

Closes #38171

---------

Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-01 10:03:38 +00:00
458c11bd68 fix(actions): allow Actions bot to push to protected branches (#38284)
Fixes #38278

## Problem

When branch protection matches the branch an Actions workflow pushes to,
the runner's `git push` is rejected — even though the workflow token has
`contents: write` and the same push performed with a PAT (write access)
succeeds. Disabling protection or changing the pattern so it no longer
matches makes the push work.

## Root cause

In `preReceiveBranch` (`routers/private/hook_pre_receive.go`), the "can
the doer push to this protected branch" check resolves the pusher with
`user_model.GetUserByID(ctx, ctx.opts.UserID)`. For an Actions push the
user ID is `-2` (the virtual `ActionsUserID`), which has no database
row, so the lookup fails. Even past that, `CanUserPush` →
`HasAccessUnit`/whitelist membership cannot evaluate a virtual user and
returns `false`. As a result the Actions bot was rejected on every
matching protected branch, despite the earlier `assertCanWriteRef`
already confirming the token's code-write via
`GetActionsUserRepoPermission`.

This was inconsistent: a PAT with identical write access passed the
exact same check.

## Fix

Evaluate the Actions bot against its already-computed token permission
instead of a user lookup, mirroring the existing
`IsUserMergeWhitelisted` pattern:

- Add `CanActionsUserPush` / `CanActionsUserForcePush` on
`ProtectedBranch`, which take the precomputed `access_model.Permission`.
- Allow the push when push is enabled, **no** push whitelist is
enforced, and the token has code-write.
- Keep the bot blocked when a whitelist is enforced — it cannot be added
to one, so it must use a pull request. This preserves the whitelist as a
real security boundary.

Force-push, signed-commit and protected-file-path checks are untouched.

---------

Signed-off-by: bircni <bircni@icloud.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-01 09:19:47 +00:00
GiteaBot 3d2bbd25ec [skip ci] Updated translations via Crowdin 2026-07-01 01:19:35 +00:00
Avinash ThakurandGitHub 7745720292 feat: extend <video> tag allowed attributes (#38279)
autoplay is useless nowadays without "muted" as browsers won't autoplay
unmuted videos.
Similarly, other attributes are also commonly used and harmless to keep.

<!--
Before submitting:
- Target the `main` branch; release branches are for backports only.
- Use a Conventional Commits title, e.g. `fix(repo): handle empty branch
names`.
- Read the contributing guidelines:
https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md
- Documentation changes go to https://gitea.com/gitea/docs

Describe your change below and link any issue it fixes.
-->

---------

Signed-off-by: Avinash Thakur <19588421+80avin@users.noreply.github.com>
2026-06-30 20:31:13 +00:00
bircniandGitHub d46d0540d0 fix(actions): include all aggregable run statuses in status filter (#38280)
The **Status** filter dropdown on the repository Actions run list does
not let you filter for **Blocked** runs (nor **Cancelled** or
**Skipped**). These statuses are missing from the dropdown even though a
run can legitimately end up in any of them.

A run's status is computed by `aggregateJobStatus`, which can return
`Blocked`, `Cancelled` and `Skipped`. Because the filter dropdown only
offered Success, Failure, Waiting, Running and Cancelling, runs in those
other states existed but were impossible to filter for.
2026-06-30 19:59:30 +00:00
techknowlogickandGitHub e449018730 non-shallow clone for snapcraft
Signed-off-by: techknowlogick <techknowlogick@gitea.com>
2026-06-30 18:35:29 +02:00
e1cdb71845 fix(archiver): use serializable repo-archive queue payload (#38273)
After upgrading from 1.25.x to 1.26.x, `repo-archive` workers can fail
to unmarshal queued items:

```
Failed to unmarshal item from queue "repo-archive":
json: unable to unmarshal into Go convert.Conversion within "/Repo/Units/0/Config":
cannot derive concrete type for nil interface with finite type set
```

`ArchiveRequest` started embedding `*repo_model.Repository` in 1.26,
which does not round-trip through the JSON queue.

This change stores a minimal `archiveQueueItem` (`RepoID`, `Type`,
`CommitID`, `Paths`) in `repo-archive` and loads the repository in the
worker. `UnmarshalJSON` accepts legacy payloads that used `RepoID` or
embedded `Repo.id`.

Fixes #38272

<!--
Before submitting:
- Target the `main` branch; release branches are for backports only.
- Use a Conventional Commits title, e.g. `fix(repo): handle empty branch
names`.
- Read the contributing guidelines:
https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md
- Documentation changes go to https://gitea.com/gitea/docs

Describe your change below and link any issue it fixes.
-->

---------

Co-authored-by: bircni <bircni@icloud.com>
2026-06-30 14:42:05 +00:00
silverwindandGitHub a64131e22d chore: update eslint plugins and config (#38264)
1. Bump all eslint dependencies, enable some of the new unicorn rules
2. Remove `eslint-plugin-de-morgan`, it sometimes causes readability
issues
3. Disable some of the unicorn rules that are known to produce
false-positives
4. Remove obsolete type cast
5. Fix one violation of
https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-dom-node-replace-children.md

---------

Signed-off-by: silverwind <me@silverwind.io>
2026-06-30 13:53:29 +00:00
GiteaBot 0f0a38c1b9 [skip ci] Updated translations via Crowdin 2026-06-30 01:13:52 +00:00
silverwindandGitHub 535f791166 ci: regenerate codemirror languages on renovate npm updates (#38267)
Adds `make generate-codemirror-languages` to the npm group's
`postUpgradeTasks` in `renovate.json5`, so renovate regenerates
`assets/codemirror-languages.json` whenever `@codemirror/language-data`
(or any npm dep) updates — mirroring the existing `make svg` handling.

Also reformats the `fileFilters` arrays multi-line and regenerates the
asset to pick up current upstream linguist languages.
2026-06-29 22:59:08 +00:00
b34a09be38 build: fix snapcraft release (#38260)
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: silverwind <me@silverwind.io>
2026-06-29 14:35:26 -07:00
6f2e328c85 chore(deps): update dependency js-yaml to v5 (#38262)
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [js-yaml](https://redirect.github.com/nodeca/js-yaml) | [`4.2.0` →
`5.1.0`](https://renovatebot.com/diffs/npm/js-yaml/4.2.0/5.1.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/js-yaml/5.1.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/js-yaml/4.2.0/5.1.0?slim=true)
|

---

### Release Notes

<details>
<summary>nodeca/js-yaml (js-yaml)</summary>

###
[`v5.1.0`](https://redirect.github.com/nodeca/js-yaml/blob/HEAD/CHANGELOG.md#510---2026-06-23)

[Compare
Source](https://redirect.github.com/nodeca/js-yaml/compare/5.0.0...5.1.0)

##### Added

- Collection tags can finalize an incrementally populated carrier into a
  different result value.

##### Changed

- \[breaking] `quoteStyle` now selects the preferred quote style; use
the
  restored `forceQuotes` option to force quoting non-key strings.

###
[`v5.0.0`](https://redirect.github.com/nodeca/js-yaml/blob/HEAD/CHANGELOG.md#500---2026-06-20)

[Compare
Source](https://redirect.github.com/nodeca/js-yaml/compare/4.3.0...5.0.0)

##### Added

- Added named exports for schemas, tags, parser events and AST
utilities.
- Reworked `JSON_SCHEMA` and `CORE_SCHEMA` with spec-compliant scalar
resolution
  rules, and added `YAML11_SCHEMA`.
- Added `realMapTag` for lossless mappings with non-string and complex
keys.
Object-based mappings now reject complex keys instead of stringifying
them.
- Added `dump()` `transform` option for changing the generated AST
before
  rendering.
- Added `dump()` options `seqInlineFirst`, `flowBracketPadding`,
`flowSkipCommaSpace`, `flowSkipColonSpace`, `quoteFlowKeys`,
`quoteStyle` and
  `tagBeforeAnchor`.
- Added formal data layers (events and AST) for modular data pipelines.
  - Added low-level parser (to events), presenter and visitor APIs.
- Added the [YAML Test
Suite](https://redirect.github.com/yaml/yaml-test-suite) to the
  test set.

##### Changed

- See the [migration guide](docs/migrate_v4_to_v5.md) for upgrade notes.
- Rewritten in TypeScript and reorganized the public API around flat
named
  exports.
- Reduced the set of exported schemas:
  - YAML 1.2 schemas: `CORE_SCHEMA` (loader default), `JSON_SCHEMA`,
    `FAILSAFE_SCHEMA`.
- `YAML11_SCHEMA`, a combination of all YAML 1.1 tags (YAML 1.1 does not
    specify a schema, only "types").
- `load`/`dump` default behaviour is now specified exactly via schemas:
  - `load` uses `CORE_SCHEMA`, without `!!merge` by default.
- `dump` uses `YAML11_SCHEMA` + `CORE_SCHEMA` for the quoting check, to
    guarantee backward compatibility by default.
- `!!set` is now loaded as a JavaScript `Set`.
- Replaced the `Type` API with a tags API. Similar, but more precise and
  simpler. See examples for details. Tags can be defined via
`defineScalarTag()`, `defineSequenceTag()` and `defineMappingTag()`, or
as a
  spread + override of an existing tag.
- Renamed `Schema.extend()` to `Schema.withTags()`.
- Expanded YAML 1.2 conformance and improved handling of directives,
document
  markers, block keys, multiline scalars, tag syntax and other things.
- `load()` now throws on empty input instead of returning `undefined`.
- Moved browser builds to the `js-yaml/browser` export.
- Deprecated the `loadAll` signature with an iterator (still works, but
is a
  candidate for removal).

##### Removed

- Removed deprecated `safeLoad()`, `safeLoadAll()` and `safeDump()`
exports.
- Removed `DEFAULT_SCHEMA` and the nested `types` export.
- Removed loader options `onWarning`, `legacy` and `listener`.
- Removed dumper options `styles`, `replacer`, `noCompatMode`,
`condenseFlow`,
`quotingType` and `forceQuotes`. Renamed `noArrayIndent` to
`seqNoIndent`.
Formatting and representation are now configured through presenter
options,
  schemas and tag definitions. See migration guide on how to replace.
- Removed support for importing internal files from `lib/`.

###
[`v4.3.0`](https://redirect.github.com/nodeca/js-yaml/blob/HEAD/CHANGELOG.md#430-3150---2026-06-27)

[Compare
Source](https://redirect.github.com/nodeca/js-yaml/compare/4.2.0...4.3.0)

##### Security

- Backported `maxTotalMergeKeys` option.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Only on Monday (`* * * * 1`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNDEuNSIsInVwZGF0ZWRJblZlciI6IjQzLjE0MS41IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->

---------

Co-authored-by: silverwind <me@silverwind.io>
2026-06-29 17:22:21 +00:00
GiteabotandGitHub 55983320ed chore(deps): update actions/cache action to v6 (#38261)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [actions/cache](https://redirect.github.com/actions/cache) | action |
major | `v5.0.5` → `v6.1.0` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/37531) for more information.

---

### Release Notes

<details>
<summary>actions/cache (actions/cache)</summary>

###
[`v6.1.0`](https://redirect.github.com/actions/cache/releases/tag/v6.1.0)

[Compare
Source](https://redirect.github.com/actions/cache/compare/v6.0.0...v6.1.0)

##### What's Changed

- Bump
[@&#8203;actions/cache](https://redirect.github.com/actions/cache) to
v6.1.0 - handle read-only cache access by
[@&#8203;jasongin](https://redirect.github.com/jasongin) in
[#&#8203;1768](https://redirect.github.com/actions/cache/pull/1768)

**Full Changelog**:
<https://github.com/actions/cache/compare/v6...v6.1.0>

###
[`v6`](https://redirect.github.com/actions/cache/compare/v6.0.0...v6.0.0)

[Compare
Source](https://redirect.github.com/actions/cache/compare/v6.0.0...v6.0.0)

###
[`v6.0.0`](https://redirect.github.com/actions/cache/releases/tag/v6.0.0)

[Compare
Source](https://redirect.github.com/actions/cache/compare/v5.1.0...v6.0.0)

##### What's Changed

- Update packages, migrate to ESM by
[@&#8203;Samirat](https://redirect.github.com/Samirat) in
[#&#8203;1760](https://redirect.github.com/actions/cache/pull/1760)

**Full Changelog**:
<https://github.com/actions/cache/compare/v5...v6.0.0>

###
[`v5.1.0`](https://redirect.github.com/actions/cache/releases/tag/v5.1.0)

[Compare
Source](https://redirect.github.com/actions/cache/compare/v5.0.5...v5.1.0)

##### What's Changed

- Bump
[@&#8203;actions/cache](https://redirect.github.com/actions/cache) to
v5.1.0 - handle read-only cache access by
[@&#8203;jasongin](https://redirect.github.com/jasongin) in
[#&#8203;1775](https://redirect.github.com/actions/cache/pull/1775)

**Full Changelog**:
<https://github.com/actions/cache/compare/v5...v5.1.0>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Only on Monday (`* * * * 1`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNDEuNSIsInVwZGF0ZWRJblZlciI6IjQzLjE0MS41IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->
2026-06-29 17:00:15 +00:00
68 changed files with 1521 additions and 1427 deletions
+6 -6
View File
@@ -16,34 +16,34 @@ runs:
using: composite
steps:
- if: ${{ github.workflow == 'cache-seeder' }}
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/go/pkg/mod
key: gomod-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
- if: ${{ github.workflow != 'cache-seeder' }}
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/go/pkg/mod
key: gomod-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
restore-keys: gomod-${{ runner.os }}-${{ runner.arch }}
- if: ${{ github.workflow == 'cache-seeder' && inputs.lint-cache != 'true' }}
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/go-build
key: gobuild-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
- if: ${{ github.workflow != 'cache-seeder' || inputs.lint-cache == 'true' }}
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/go-build
key: gobuild-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
restore-keys: gobuild-${{ runner.os }}-${{ runner.arch }}
- if: ${{ inputs.lint-cache == 'true' && github.workflow == 'cache-seeder' }}
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/golangci-lint
key: golint-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum', '.golangci.yml') }}
- if: ${{ inputs.lint-cache == 'true' && github.workflow != 'cache-seeder' }}
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/golangci-lint
key: golint-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum', '.golangci.yml') }}
+2 -2
View File
@@ -13,10 +13,10 @@ runs:
- if: ${{ inputs.cache == 'true' }}
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
node-version: 26
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- if: ${{ inputs.cache != 'true' }}
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
node-version: 26
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
ref: ${{ github.event.pull_request.base.sha }}
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
node-version: 26
# Labels are only synced after the title lints, so an invalid title never reaches the label diff.
- run: node ./tools/ci-tools.ts lint-pr-title
env:
+21 -27
View File
@@ -6,40 +6,34 @@ on:
- main
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build-and-publish:
runs-on: ubuntu-latest
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
strategy:
fail-fast: false
matrix:
runner: [ubuntu-24.04, ubuntu-24.04-arm]
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
fetch-depth: 0
- name: Install snapcraft
run: sudo snap install snapcraft --classic
- name: Build snap
id: build
uses: snapcore/action-build@3bdaa03e1ba6bf59a65f84a751d943d549a54e79 # v1.3.0
- name: Authenticate snapcraft
shell: bash
run: snapcraft login --with <(printf '%s' "$SNAPCRAFT_STORE_CREDENTIALS")
- name: Remote build
run: |
snapcraft remote-build \
--launchpad-accept-public-upload \
--build-for=amd64,arm64,armhf
- name: List built snaps
run: find . -maxdepth 1 -type f -name '*.snap' -print
- name: Upload and release snapcraft nightly build
run: |
set -euo pipefail
for snap in ./*.snap; do
echo "Uploading $snap to edge"
snapcraft upload --release="latest/edge" "$snap"
done
- name: Upload and release nightly build to latest/edge
uses: snapcore/action-publish@214b86e5ca036ead1668c79afb81e550e6c54d40 # v1.2.0
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
with:
snap: ${{ steps.build.outputs.snap }}
release: latest/edge
+1 -6
View File
@@ -23,12 +23,7 @@ jobs:
with:
go-version-file: go.mod
check-latest: true
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- uses: ./.github/actions/node-setup
- run: make deps-frontend deps-backend
# xgo build
- run: make release
+1 -6
View File
@@ -24,12 +24,7 @@ jobs:
with:
go-version-file: go.mod
check-latest: true
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- uses: ./.github/actions/node-setup
- run: make deps-frontend deps-backend
# xgo build
- run: make release
+1 -6
View File
@@ -27,12 +27,7 @@ jobs:
with:
go-version-file: go.mod
check-latest: true
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- uses: ./.github/actions/node-setup
- run: make deps-frontend deps-backend
# xgo build
- run: make release
-268
View File
@@ -4,274 +4,6 @@ This changelog goes through the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.com).
## [1.27.0-rc0](https://github.com/go-gitea/gitea/releases/tag/v1.27.0-rc0) - 2026-06-28
* BREAKING
* Feat(actions)!: improve support for reusable workflows (#37478)
* Use Content-Security-Policy: script nonce (#37232)
* SECURITY
* Fix(deps): update module github.com/go-git/go-git/v5 to v5.19.1 [security] (#37786)
* Fix(oauth): restrict introspection to the token's client (#38042)
* Fix(api): don't expose private org membership via public_members (#38145)
* Fix(actions): deny fork-PR cross-repo access via collaborative owner (#38214)
* Fix(migrations): prevent path traversal in repository restore (#38215)
* FEATURES
* Feat(actions): add workflow status badge modal (#38196)
* Feat(actions): support owner-level and global scoped workflows (#38154)
* Feat(api): support ref suffixes in compare (#38148)
* Feat(actions): implement `jobs.<job_id>.continue-on-error` (#38100)
* Feat(actions): show run status on browser tab favicon (#38071)
* Feat(api): add token introspection and self-deletion endpoint (#37995)
* Feat(api): add q parameter to list branches API for server-side filtering (#37982)
* Feat(repo): split repository creation limit into user and org scopes (#37872)
* Feat(actions): bulk delete, disable and enable runners in admin UI (#37869)
* Feat(actions): List workflows that were executed once but got removed from the default branch (#37835)
* Feat(org): add team visibility so org members can discover teams (#37680)
* Feat: add raw diff/patch endpoint for repository comparisons (#37632)
* Feat: Add avatar stacks (#37594)
* Feat(actions): add job summaries (GITHUB_STEP_SUMMARY) (#37500)
* Feat(web): Add Jupyter Notebook (.ipynb) Rendering Support (#37433)
* Support for Custom URI Schemes in OAuth2 Redirect URIs (#37356)
* Feat(orgs): Add search bar for organization members tab page (#37347)
* Feat(api): Add assignees APIs (#37330)
* Feat(api): Add GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs (#37196)
* Serve OpenAPI 3.0 spec at /openapi.v1.json (#37038)
* Add project column picker to issue and pull request sidebar (#37037)
* Allow multiple projects per issue and pull requests (#36784)
* Feat(ui): add "follow rename" to file commit history list (#34994)
* Feat(ssh): auto generate additional ssh keys (#33974)
* ENHANCEMENTS
* Enhance: allow builtin default git config options to be overridden (#38172)
* Enhance: allow MathML core elements (#38034)
* Enhance(markup): improve issue title rendering (#37908)
* Enhance(actions): set descriptive browser tab title on run view (#37870)
* Enhance: Migrate remaining gopkg.in/yaml.v3 usages to go.yaml.in/yaml/v4 (#37866)
* Enhance(actions): show workflow name from YAML instead of filename (#37833)
* Feat(actions): add before/after to PR synchronize event payload (#37827)
* Enhance(actions): add branch filters to run list (#37826)
* Enhance(actions): Make Summary UI more beautiful with more infos (#37824)
* Feat: add copy button to action step header, improve other copy buttons (#37744)
* Fix(icon): use repo-forked icon to display forks count (#37731)
* Feat(api): add sort and order query parameters to job list endpoints (#37672)
* Feat(api): add last_sync to repository API (#37566)
* Enhance: Adjust Workflow Graph styling (#37497)
* Improve code editor text selection and clean up lint enablement (#37474)
* Add mirror auth updates to repo edit API and settings (#37468)
* Replace `olivere/elastic` with REST API client, add OpenSearch support (#37411)
* Feat: Add default PR branch update style setting (#37410)
* Fix inconsistent disabled styling on logged-out repo header buttons (#37406)
* Allow fast-forward-only merge when signed commits are required (#37335)
* Enhance styling in actions page (#37323)
* Fix: improve actions status icons and texts (#37206)
* Make Markdown fenced code block work with more syntaxes (#37154)
* Fix: Sort action run jobs by JobID and Name with matrix examples (#37046)
* Add API endpoint to reply to pull request review comments (#36683)
* PERFORMANCE
* Perf(web): sort the action_run query by a repo-scoped index when possible (#38155)
* Perf: Various performance regression fixes (#38078)
* Perf: extend action `c_u` index to include `created_unix` for faster dashboard feeds (#38076)
* Batch-load related data in actions run, job, and task API endpoints (#37032)
* BUGFIXES
* Fix: update npm dependencies, fix misc issues (#38257)
* Fix(api): respect since/until when counting commits for X-Total-Count (#38204)
* Fix: codemirror regressions (#38248)
* Fix(api): support HEAD requests on all API GET endpoints (#38245)
* Fix(actions): Cleanup workflow status badge code (#38241)
* Fix(web): Correctly align the "disabled" label on larger workflow names (#38240)
* Fix(actions): don't swallow HTML entities into linkified URLs (#38239)
* Fix(packages): accept npm "repository" and "bin" in string form (#38236)
* Fix(actions): fix 500 error when canceling a canceling task (#38223)
* Fix(deps): update module golang.org/x/image to v0.43.0 [security] (#38219)
* Fix(mssql): convert legacy DATETIME columns to DATETIME2 (#38216)
* Fix(api): deny private org member enumeration via /members (#38213)
* Fix(actions): ensure all waiting jobs get runners in large workflows (#38200)
* Fix(deps): update go dependencies (#38194)
* Fix(deps): update npm dependencies (#38193)
* Fix(cli): default must-change-password to false for bot users (#38175)
* Fix(actions): show run index in run view and fix summary graph height (#38165)
* Fix: csp (#38162)
* Fix(deps): update npm dependencies (#38123)
* Fix(mssql): expand legacy issue and comment long-text columns (#38120)
* Fix(packages): validate debian distribution and component names (#38116)
* Fix(packages): validate module version in goproxy ParsePackage (#38104)
* Fix(deps): update dependency esbuild to v0.28.1 [security] (#38097)
* Fix: git push hook post receive (#38089)
* Fix(ui): prevent commit status popup overflowing its row (#38081)
* Fix: validate gem name in rubygems parseMetadataFile (#38061)
* Fix: commit display name (#38057)
* Fix: csp regressions (#38047)
* Fix: api error message (#38031)
* Fix(deps): update npm dependencies (#38029)
* Fix: pgsql lint (#38022)
* Fix(indexer): fix assignee filters in issue search (#38021)
* Fix: various dropdown problems (#38020)
* Fix: refactor git error handling and make archive streaming handle non-existing commit id (#38007)
* Fix: raise git required version to 2.13 (#37996)
* Fix: remove "no-transfrom" from the cache-control header (#37985)
* Fix(deps): update module github.com/google/go-github/v87 to v88 (#37971)
* Fix: use committer time where ever possible as default (#37969)
* Fix(deps): update npm dependencies, remove nolyfill (#37968)
* Fix(deps): update go dependencies (#37967)
* Fix(pull): preserve squash message trailers and additional commit messages (#37954)
* Fix(deps): update module golang.org/x/image to v0.41.0 [security] (#37904)
* Fix: support ##[command] log prefix in action run UI (#37882)
* Fix(deps): update module github.com/google/go-github/v86 to v87 (#37845)
* Fix(deps): update npm dependencies (#37844)
* Fix(deps): update go dependencies (#37841)
* Fix(frontend): resolve Vite assets by manifest source path (#37836)
* Fix(locales): Replace hardcoded strings (#37788)
* Fix(packages): render markdown links relative to linked repo (#37676)
* Fix: persist mirror repository metadata (#37519)
* Fix cmd tests by mocking builtin paths (#37369)
* Add `form-fetch-action` to some forms, fix "fetch action" resp bug (#37305)
* Feat: execute post run cleanup when workflow is cancelled (#37275)
* Fix `relative-time` error and improve global error handler (#37241)
* Refactor flash message and remove SanitizeHTML template func (#37179)
* TESTING
* Test: speed up two tests (#37905)
* Test: Fix random failure test (#37887)
* Test: fix flaky `issue-comment` close test (#37880)
* Test: enable WAL for sqlite integration tests (#37861)
* Test: fix flaky `TestResourceIndex` and reduce its runtime (#37847)
* Test: run `TestAPIRepoMigrate` offline via a local clone source (#37817)
* Ci: shard tests and reduce redundant work (#37618)
* Test(e2e): run playwright via container (#37300)
* Remove external service dependencies in migration tests (#36866)
* BUILD
* Fix(actions): authenticate snapcraft before nightly remote build (#38252)
* Ci: cap Elasticsearch heap in db-tests (#37816)
* Build(snap): publish nightly version to snapcraft via actions (#37814)
* Ci: split pgsql shards into plain jobs, dedupe setup actions (#37802)
* Ci: narrow files-changed frontend filter (#37749)
* Ci: add `zizmor` to `lint-actions` (#37720)
* Chore: clean up "contrib" dir (#37690)
* Fix: snap build (main branch) (#37685)
* Ci: Also lint json5 files (#37659)
* Feat(editor): broaden language detection in web code editor (#37619)
* Build: update pnpm to v11 (#37591)
* Refactor(deps): migrate from `nektos/act` fork to `gitea/runner` (#37557)
* Refactor: lint bare `fill`/`stroke` colors, add vars for git graph color series (#37543)
* Update go js py dependencies (#37525)
* Ci: lint PR titles with commitlint (#37498)
* Chore: upgrade Go version in devcontainer image to 1.26 (#37374)
* Update GitHub Actions to latest major versions (#37313)
* Update go js dependencies (#37312)
* Fail vite build on rolldown warnings via NODE_ENV=test (#37270)
* Remove htmx (#37224)
* Replace custom Go formatter with `golangci-lint fmt` (#37194)
* Refactor htmx and fetch-action related code (#37186)
* Integrate renovate bot for all dependency updates (#37050)
* Build(sign): move to sigstore (#38250)
* DOCS
* Docs: update changelog for 1.26.3 & 1.26.4 (#38178)
* Docs: fix duplicated word in foreachref doc comment (#38161)
* Docs: Clarify criteria for becoming a merger (#38113)
* Docs: Publish TOC Election Result 2026 (#38111)
* Docs: mark openapi3 as autogenerated in attributes (#37963)
* Docs: add development setup guide (#37960)
* MISC
* Revert(sign): restore gpg (#38251)
* Refactor: replace legacy `delete-button` with `link-action` (#38143)
* Refactor(actions): read runner capabilities from proto field (#38068)
* Refactor(api): clarify APIError message usage and fix legacy lint error (#38012)
* Refactor: Use db.Get[] instead of db.GetEngine(ctx).Get(bean) to avoid zero value fetching wrong database record (#37977)
* Fix(deps): update go dependencies (#37851)
* Ci: Fix sync PR labels from the conventional-commit title (#37784) (#37825)
* Ci: tweak `files-changed`, add `free-disk-space` (#37819)
* Fix(deps): update module golang.org/x/crypto to v0.52.0 [security] (#37806)
* Test(e2e): add comment, release, star, PR and fork tests (#37800)
* Chore: simplify issue and pull request templates (#37799)
* Chore: Update giteabot to fix failure when backport (#37789)
* Fix(api): handle partial failures in push mirror synchronization gracefully (#37782)
* Fix(deps): update module gitlab.com/gitlab-org/api/client-go/v2 to v2.26.0 (#37771)
* Ci: split giteabot workflow (#37770)
* Fix(deps): update npm dependencies (#37768)
* Refactor(waitgroup): replace Add/Done goroutines with WaitGroup.Go (#37764)
* Fix(deps): update module google.golang.org/grpc to v1.81.1 (#37762)
* Ci: fix cache-related issues (#37761)
* Chore: fix tests (#37760)
* Fix(deps): update module github.com/google/go-github/v85 to v86 (#37754)
* Fix(deps): update npm dependencies (#37753)
* Fix(deps): update go dependencies (#37752)
* Chore(deps): update action dependencies (#37751)
* Fix(markup): wrap indented code blocks for the code-copy button (#37748)
* Chore(db): introduce db.Session and db.EngineMigration interfaces (#37746)
* Feat(web): also display PR counts in repo list (#37739)
* Refactor(glob): use strings.Builder for regexp compilation (#37730)
* Chore(doctor): remove four obsolete doctor check implementations (#37728)
* Refactor(org): simplify owner-team org repo creation logic (#37727)
* Refactor: move `workflowpattern` into `modules/actions` (#37717)
* Chore: clean up tests (#37715)
* Style: misc UI fixes (#37691)
* Ci: add shellcheck linter (#37682)
* Fix: catch and fix more lint problems (#37674)
* Fix(deps): update dependency mermaid to v11.15.0 [security], add e2e test (#37662)
* Fix(deps): update npm dependencies (#37647)
* Ci(renovate): update Go import paths on major bumps (#37641)
* Fix(deps): update go dependencies (major) (#37639)
* Chore(deps): update action dependencies (major) (#37638)
* Fix(deps): update module code.gitea.io/sdk/gitea to v0.25.0 (#37637)
* Fix(deps): update npm dependencies (#37636)
* Refactor(log): replace log.Critical with log.Error (#37624)
* Build(deps): bump fast-uri from 3.1.0 to 3.1.2 (#37616)
* Feat(oauth): Support AWS Cognito OAuth2 provider (#37607)
* Chore(deps): update action dependencies (#37603)
* Ci: allow `chore` type in PR title lint (#37575)
* Refactor: only reset a database table when the table's data was changed (#37573)
* Ci: increase renovate frequency and fix RENOVATE_ALLOWED_POST_UPGRADE_COMMANDS (#37565)
* Refactor: use modernc sqlite driver as default (#37562)
* Docs: fix 4 typos in CHANGELOG.md (#37549)
* Fix(deps): update go dependencies (#37541)
* Chore(deps): update action dependencies (#37540)
* Refactor pull request view (6) (#37522)
* Fix: redirect early CLI console logger to stderr (#37507)
* Refactor "flex-list" to "flex-divided-list" (#37505)
* Refactor compare diff/pull page (1) (#37481)
* Refactor pull request view (4) (#37451)
* Update 1.26.1 changelog in main (#37442)
* Refactor: use named `Permission` field in `Repository` struct instead of anonymous embedding (#37441)
* Refactor: serve site manifest via `/assets/site-manifest.json` endpoint (#37405)
* Remove IsValidExternalURL/IsAPIURL and use IsValidURL at call sites (#37364)
* Update `Block a user` form (#37359)
* Move review request functions to a standalone file (#37358)
* Feat(security): set X-Content-Type-Options: nosniff by default (#37354)
* Enable strict TypeScript, add `errorMessage` helper (#37292)
* Refactor frontend `tw-justify-between` layouts to `flex-left-right` (#37291)
* Update Nix flake (#37284)
* Fix Repository transferring page (#37277)
* Remove `SubmitEvent` polyfill (#37276)
* Remove dead code identified by `deadcode` tool (#37271)
* Upgrade go-git to v5.18.0 (#37268)
* Don't add useless labels which will bother changelog generation (#37267)
* Move heatmap to first-party code (#37262)
* Tests/integration: simplify code (#37249)
* Add pagination and search box to org teams list (#37245)
* Remove error returns from crypto random helpers and callers (#37240)
* Add `ExternalIDClaim` option for OAuth2 OIDC auth source (#37229)
* Refactor: simplify ParseCatFileTreeLine and catBatchParseTreeEntries (#37210)
* Refactor "htmx" to "fetch action" (#37208)
* Update go js py dependencies (#37204)
* Add comment for the design of "user activity time" (#37195)
* Remove outdated RunUser logic (#37180)
* Models/fixtures: add "DO NOT add more test data" comment to all yml fixture files (#37150)
* Update javascript dependencies (#37142)
* Update go dependencies (#37141)
* Frontport changelog of v1.26.0-rc0 (#37138)
* Introduce `ActionRunAttempt` to represent each execution of a run (#37119)
* Workflow Artifact Info Hover (#37100)
* Extend issue context popup beyond markdown content (#36908)
* Add bulk repository deletion for organizations (#36763)
* Feat: Add bypass allowlist for branch protection (#36514)
## [1.26.4](https://github.com/go-gitea/gitea/releases/tag/1.26.4) - 2026-06-21
* SECURITY
+9 -5
View File
@@ -16,7 +16,7 @@ EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-che
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2 # renovate: datasource=go
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.15 # renovate: datasource=go
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.8.0 # renovate: datasource=go
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.34.1 # renovate: datasource=go
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.35.0 # renovate: datasource=go
XGO_PACKAGE ?= src.techknowlogick.com/xgo@v1.9.0 # renovate: datasource=go
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1.4.0 # renovate: datasource=go
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.12 # renovate: datasource=go
@@ -231,7 +231,9 @@ endif
generate-swagger: $(SWAGGER_SPEC) $(OPENAPI3_SPEC) ## generate the swagger spec from code comments
$(SWAGGER_SPEC): $(GO_SOURCES) $(SWAGGER_SPEC_INPUT)
$(GO) run $(SWAGGER_PACKAGE) generate spec --exclude "$(SWAGGER_EXCLUDE)" --input "$(SWAGGER_SPEC_INPUT)" --output './$(SWAGGER_SPEC)'
@output="$$($(GO) run $(SWAGGER_PACKAGE) generate spec --enable-allof-compounding --skip-enum-desc --exclude "$(SWAGGER_EXCLUDE)" --input "$(SWAGGER_SPEC_INPUT)" --output './$(SWAGGER_SPEC)' 2>&1)" || { printf '%s\n' "$$output" >&2; exit 1; }; \
warnings="$$(printf '%s\n' "$$output" | grep -v '^go: ')"; \
if [ -n "$$warnings" ]; then printf '%s\n' "$$warnings" >&2; exit 1; fi
.PHONY: swagger-check
swagger-check: generate-swagger
@@ -246,9 +248,11 @@ swagger-check: generate-swagger
swagger-validate: ## check if the swagger spec is valid
@# swagger "validate" requires that the "basePath" must start with a slash, but we are using Golang template "{{...}}"
@$(SED_INPLACE) -E -e 's|"basePath":( *)"(.*)"|"basePath":\1"/\2"|g' './$(SWAGGER_SPEC)' # add a prefix slash to basePath
@# FIXME: there are some warnings
$(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)'
@$(SED_INPLACE) -E -e 's|"basePath":( *)"/(.*)"|"basePath":\1"\2"|g' './$(SWAGGER_SPEC)' # remove the prefix slash from basePath
@output="$$($(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)' 2>&1)"; status=$$?; \
$(SED_INPLACE) -E -e 's|"basePath":( *)"/(.*)"|"basePath":\1"\2"|g' './$(SWAGGER_SPEC)'; \
printf '%s\n' "$$output" | grep -v '^go: '; \
[ $$status -eq 0 ] || exit $$status; \
case "$$output" in *WARNING:*) exit 1;; esac
.PHONY: generate-openapi3
generate-openapi3: $(OPENAPI3_SPEC) ## generate the OpenAPI 3.0 spec from the Swagger 2.0 spec
+8
View File
@@ -436,6 +436,7 @@
"jsonl",
"mcmeta",
"sarif",
"slnlaunch",
"tact",
"tfstate",
"topojson",
@@ -691,10 +692,17 @@
"extensions": [
"ini",
"cnf",
"container",
"dof",
"lektorproject",
"mount",
"network",
"prefs",
"properties",
"service",
"socket",
"target",
"timer",
"url",
"conf"
],
+1
View File
@@ -18,6 +18,7 @@ func newUserCommand() *cli.Command {
microcmdUserDelete(),
newUserGenerateAccessTokenCommand(),
microcmdUserMustChangePassword(),
microcmdUserDisableTwoFactor(),
},
}
}
+72
View File
@@ -0,0 +1,72 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"context"
"errors"
"fmt"
"strings"
auth_model "gitea.dev/models/auth"
user_model "gitea.dev/models/user"
"gitea.dev/modules/setting"
"github.com/urfave/cli/v3"
)
func microcmdUserDisableTwoFactor() *cli.Command {
return &cli.Command{
Name: "disable-2fa",
Usage: "Disable two-factor authentication for a user",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "username",
Aliases: []string{"u"},
Usage: "Username of the user to disable 2FA for",
},
&cli.Int64Flag{
Name: "id",
Usage: "ID of the user to disable 2FA for",
},
},
Action: runDisableTwoFactor,
}
}
func runDisableTwoFactor(ctx context.Context, c *cli.Command) error {
if !c.IsSet("id") && !c.IsSet("username") {
return errors.New("either --id or --username must be provided")
}
if !setting.IsInTesting {
if err := initDB(ctx); err != nil {
return err
}
}
var user *user_model.User
var err error
if c.IsSet("id") {
user, err = user_model.GetUserByID(ctx, c.Int64("id"))
} else {
user, err = user_model.GetUserByName(ctx, c.String("username"))
}
if err != nil {
return err
}
// When both selectors are given, make sure they refer to the same user.
if c.IsSet("id") && c.IsSet("username") && user.LowerName != strings.ToLower(strings.TrimSpace(c.String("username"))) {
return fmt.Errorf("the user with id %d is %q, which does not match the provided username %q", user.ID, user.Name, c.String("username"))
}
totp, webAuthn, err := auth_model.DisableTwoFactor(ctx, user.ID)
if err != nil {
return err
}
fmt.Printf("Disabled 2FA for user %q (removed %d TOTP and %d WebAuthn credential(s))\n", user.Name, totp, webAuthn)
return nil
}
+119
View File
@@ -0,0 +1,119 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"io"
"strconv"
"testing"
auth_model "gitea.dev/models/auth"
"gitea.dev/models/db"
"gitea.dev/models/unittest"
user_model "gitea.dev/models/user"
"github.com/go-webauthn/webauthn/webauthn"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDisableTwoFactorCommand(t *testing.T) {
ctx := t.Context()
defer func() {
require.NoError(t, db.TruncateBeans(t.Context(), &user_model.User{}, &auth_model.TwoFactor{}, &auth_model.WebAuthnCredential{}))
}()
t.Run("disable TOTP and WebAuthn", func(t *testing.T) {
require.NoError(t, microcmdUserCreate().Run(ctx, []string{"create", "--username", "tfuser", "--email", "tfuser@gitea.local", "--random-password"}))
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "tfuser"})
// Enroll TOTP.
tf := &auth_model.TwoFactor{UID: user.ID}
require.NoError(t, tf.SetSecret("test-secret"))
_, err := tf.GenerateScratchToken()
require.NoError(t, err)
require.NoError(t, auth_model.NewTwoFactor(ctx, tf))
// Register a WebAuthn credential.
_, err = auth_model.CreateCredential(ctx, user.ID, "test-key", &webauthn.Credential{ID: []byte("test-cred-id")})
require.NoError(t, err)
has, err := auth_model.HasTwoFactorOrWebAuthn(ctx, user.ID)
require.NoError(t, err)
require.True(t, has)
require.NoError(t, microcmdUserDisableTwoFactor().Run(ctx, []string{"disable-2fa", "--username", "tfuser"}))
// Both factors must be gone afterwards.
has, err = auth_model.HasTwoFactorOrWebAuthn(ctx, user.ID)
require.NoError(t, err)
assert.False(t, has)
})
t.Run("disable by id", func(t *testing.T) {
require.NoError(t, microcmdUserCreate().Run(ctx, []string{"create", "--username", "iduser", "--email", "iduser@gitea.local", "--random-password"}))
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "iduser"})
tf := &auth_model.TwoFactor{UID: user.ID}
require.NoError(t, tf.SetSecret("test-secret"))
require.NoError(t, auth_model.NewTwoFactor(ctx, tf))
require.NoError(t, microcmdUserDisableTwoFactor().Run(ctx, []string{"disable-2fa", "--id", strconv.FormatInt(user.ID, 10)}))
has, err := auth_model.HasTwoFactorOrWebAuthn(ctx, user.ID)
require.NoError(t, err)
assert.False(t, has)
})
t.Run("no enrollment is a no-op", func(t *testing.T) {
require.NoError(t, microcmdUserCreate().Run(ctx, []string{"create", "--username", "plainuser", "--email", "plainuser@gitea.local", "--random-password"}))
require.NoError(t, microcmdUserDisableTwoFactor().Run(ctx, []string{"disable-2fa", "--username", "plainuser"}))
})
t.Run("id and username must match when both given", func(t *testing.T) {
require.NoError(t, microcmdUserCreate().Run(ctx, []string{"create", "--username", "matchuser", "--email", "matchuser@gitea.local", "--random-password"}))
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "matchuser"})
id := strconv.FormatInt(user.ID, 10)
// Matching id + username is accepted.
require.NoError(t, microcmdUserDisableTwoFactor().Run(ctx, []string{"disable-2fa", "--id", id, "--username", "matchuser"}))
// Mismatched id + username is rejected.
cmd := microcmdUserDisableTwoFactor()
cmd.Writer, cmd.ErrWriter = io.Discard, io.Discard
err := cmd.Run(ctx, []string{"disable-2fa", "--id", id, "--username", "someotheruser"})
require.Error(t, err)
require.Contains(t, err.Error(), "does not match the provided username")
})
t.Run("failure cases", func(t *testing.T) {
testCases := []struct {
name string
args []string
expectedErr string
}{
{
name: "user does not exist",
args: []string{"disable-2fa", "--username", "nonexistentuser"},
expectedErr: "user does not exist",
},
{
name: "neither id nor username",
args: []string{"disable-2fa"},
expectedErr: "either --id or --username must be provided",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
cmd := microcmdUserDisableTwoFactor()
cmd.Writer, cmd.ErrWriter = io.Discard, io.Discard
err := cmd.Run(ctx, tc.args)
require.Error(t, err)
require.Contains(t, err.Error(), tc.expectedErr)
})
}
})
}
+2 -2
View File
@@ -206,7 +206,7 @@ The result of this script needs then to be published in the TOC election issue t
- 2026-06-14 ~ 2026-12-31
- Company
- [Jason Song](https://gitea.com/wolfogre) <i@wolfogre.com>
- [Yu Tian](https://gitea.com/Zettat123) <zettat123@gmail.com>
- [Lunny Xiao](https://gitea.com/lunny) <xiaolunwen@gmail.com>
- [Matti Ranta](https://gitea.com/techknowlogick) <techknowlogick@gitea.com>
- Community
@@ -227,7 +227,7 @@ Here's the history of the owners and the time they served:
- [Andrew Thornton](https://gitea.com/zeripath) - [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [6543](https://gitea.com/6543) - 2023, 2025
- [John Olheiser](https://gitea.com/jolheiser) - 2023, 2024
- [Jason Song](https://gitea.com/wolfogre) - 2023
- [Jason Song](https://gitea.com/wolfogre) - 2023, 2025
## Governance Compensation
+13 -14
View File
@@ -1,6 +1,4 @@
import arrayFunc from 'eslint-plugin-array-func';
import comments from '@eslint-community/eslint-plugin-eslint-comments';
import deMorgan from 'eslint-plugin-de-morgan';
import globals from 'globals';
import importPlugin from 'eslint-plugin-import-x';
import playwright from 'eslint-plugin-playwright';
@@ -15,7 +13,6 @@ import vue from 'eslint-plugin-vue';
import vueScopedCss from 'eslint-plugin-vue-scoped-css';
import wc from 'eslint-plugin-wc';
import {defineConfig, globalIgnores} from 'eslint/config';
import type {ESLint} from 'eslint';
import unescapedHtmlLiteral from './tools/eslint-rules/unescaped-html-literal.ts';
@@ -64,10 +61,8 @@ export default defineConfig([
'@eslint-community/eslint-comments': comments,
'@stylistic': stylistic,
'@typescript-eslint': typescriptPlugin.plugin,
'array-func': arrayFunc,
'de-morgan': deMorgan,
'gitea': {rules: {'unescaped-html-literal': unescapedHtmlLiteral}},
'import-x': importPlugin as unknown as ESLint.Plugin, // https://github.com/un-ts/eslint-plugin-import-x/issues/203
'import-x': importPlugin,
regexp,
sonarjs,
unicorn,
@@ -278,12 +273,6 @@ export default defineConfig([
'@typescript-eslint/unified-signatures': [2],
'accessor-pairs': [2],
'array-callback-return': [2, {checkForEach: true}],
'array-func/avoid-reverse': [2],
'array-func/from-map': [2],
'array-func/no-unnecessary-this-arg': [2],
'array-func/prefer-array-from': [2],
'array-func/prefer-flat-map': [0], // handled by unicorn/prefer-array-flat-map
'array-func/prefer-flat': [0], // handled by unicorn/prefer-array-flat
'arrow-body-style': [0],
'block-scoped-var': [2],
'camelcase': [0],
@@ -294,8 +283,6 @@ export default defineConfig([
'consistent-this': [0],
'constructor-super': [2],
'curly': [0],
'de-morgan/no-negated-conjunction': [2],
'de-morgan/no-negated-disjunction': [2],
'default-case-last': [2],
'default-case': [0],
'default-param-last': [0],
@@ -745,6 +732,7 @@ export default defineConfig([
'unicorn/consistent-json-file-read': [2],
'unicorn/consistent-optional-chaining': [2],
'unicorn/consistent-template-literal-escape': [2],
'unicorn/consistent-tuple-labels': [2],
'unicorn/custom-error-definition': [0],
'unicorn/default-export-style': [2],
'unicorn/dom-node-dataset': [2, {preferAttributes: true}],
@@ -814,8 +802,10 @@ export default defineConfig([
'unicorn/no-invalid-fetch-options': [2],
'unicorn/no-invalid-file-input-accept': [2],
'unicorn/no-invalid-remove-event-listener': [2],
'unicorn/no-invalid-well-known-symbol-methods': [2],
'unicorn/no-keyword-prefix': [0],
'unicorn/no-late-current-target-access': [2],
'unicorn/no-late-event-control': [2],
'unicorn/no-lonely-if': [2],
'unicorn/no-loop-iterable-mutation': [2],
'unicorn/no-magic-array-flat-depth': [0],
@@ -896,8 +886,10 @@ export default defineConfig([
'unicorn/number-literal-case': [0],
'unicorn/numeric-separators-style': [0],
'unicorn/operator-assignment': [2],
'unicorn/prefer-abort-signal-timeout': [2],
'unicorn/prefer-add-event-listener': [2],
'unicorn/prefer-add-event-listener-options': [2],
'unicorn/prefer-aggregate-error': [2],
'unicorn/prefer-array-find': [0], // handled by @typescript-eslint/prefer-find
'unicorn/prefer-array-flat': [2],
'unicorn/prefer-array-flat-map': [2],
@@ -924,9 +916,11 @@ export default defineConfig([
'unicorn/prefer-dom-node-append': [2],
'unicorn/prefer-dom-node-html-methods': [0],
'unicorn/prefer-dom-node-remove': [2],
'unicorn/prefer-dom-node-replace-children': [2],
'unicorn/prefer-dom-node-text-content': [2],
'unicorn/prefer-early-return': [0],
'unicorn/prefer-else-if': [2],
'unicorn/prefer-error-is-error': [0],
'unicorn/prefer-event-target': [2],
'unicorn/prefer-export-from': [0],
'unicorn/prefer-flat-math-min-max': [2],
@@ -966,9 +960,11 @@ export default defineConfig([
'unicorn/prefer-object-destructuring-defaults': [2],
'unicorn/prefer-object-from-entries': [2],
'unicorn/prefer-object-iterable-methods': [2],
'unicorn/prefer-observer-apis': [2],
'unicorn/prefer-optional-catch-binding': [2],
'unicorn/prefer-path2d': [2],
'unicorn/prefer-private-class-fields': [0],
'unicorn/prefer-promise-try': [2],
'unicorn/prefer-promise-with-resolvers': [2],
'unicorn/prefer-prototype-methods': [0],
'unicorn/prefer-query-selector': [2],
@@ -979,6 +975,7 @@ export default defineConfig([
'unicorn/prefer-response-static-json': [2],
'unicorn/prefer-scoped-selector': [0],
'unicorn/prefer-set-has': [0],
'unicorn/prefer-set-methods': [0],
'unicorn/prefer-set-size': [2],
'unicorn/prefer-short-arrow-method': [2],
'unicorn/prefer-simple-condition-first': [0],
@@ -1002,6 +999,7 @@ export default defineConfig([
'unicorn/prefer-switch': [0],
'unicorn/prefer-temporal': [0],
'unicorn/prefer-ternary': [0],
'unicorn/prefer-toggle-attribute': [2],
'unicorn/prefer-top-level-await': [0],
'unicorn/prefer-type-error': [0],
'unicorn/prefer-type-literal-last': [0],
@@ -1010,6 +1008,7 @@ export default defineConfig([
'unicorn/prefer-unicode-code-point-escapes': [0],
'unicorn/prefer-url-can-parse': [2],
'unicorn/prefer-url-href': [2],
'unicorn/prefer-url-search-parameters': [2],
'unicorn/prefer-while-loop-condition': [2],
'unicorn/prevent-abbreviations': [0],
'unicorn/relative-url-style': [2],
Generated
+3 -3
View File
@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1776877367,
"narHash": "sha256-EHq1/OX139R1RvBzOJ0aMRT3xnWyqtHBRUBuO1gFzjI=",
"lastModified": 1782723713,
"narHash": "sha256-oPXCU/SSUokcGaJREHibG1CBX3+s/W7orDWQOZDsEeQ=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "0726a0ecb6d4e08f6adced58726b95db924cef57",
"rev": "b5aa0fbd538984f6e3d201be0005b4463d8b09f8",
"type": "github"
},
"original": {
+1 -1
View File
@@ -34,7 +34,7 @@
# only bump toolchain versions here
go = pkgs.go_1_26;
nodejs = pkgs.nodejs_24;
nodejs = pkgs.nodejs_26;
python3 = pkgs.python314;
pnpm = pkgs.pnpm_10;
+2 -2
View File
@@ -135,8 +135,8 @@ type StatusInfo struct {
// GetStatusInfoList returns a slice of StatusInfo
func GetStatusInfoList(ctx context.Context, lang translation.Locale) []StatusInfo {
// same as those in aggregateJobStatus
allStatus := []Status{StatusSuccess, StatusFailure, StatusWaiting, StatusRunning, StatusCancelling}
// same as those in aggregateJobStatus (StatusUnknown excluded; it's the "shouldn't happen" fallback)
allStatus := []Status{StatusSuccess, StatusFailure, StatusCancelled, StatusSkipped, StatusWaiting, StatusRunning, StatusBlocked, StatusCancelling}
statusInfoList := make([]StatusInfo, 0, len(allStatus))
for _, s := range allStatus {
statusInfoList = append(statusInfoList, StatusInfo{
+3
View File
@@ -73,8 +73,11 @@ func TestGetStatusInfoList(t *testing.T) {
assert.Equal(t, []StatusInfo{
{Status: int(StatusSuccess), StatusName: StatusSuccess.String(), DisplayedStatus: "actions.status.success"},
{Status: int(StatusFailure), StatusName: StatusFailure.String(), DisplayedStatus: "actions.status.failure"},
{Status: int(StatusCancelled), StatusName: StatusCancelled.String(), DisplayedStatus: "actions.status.cancelled"},
{Status: int(StatusSkipped), StatusName: StatusSkipped.String(), DisplayedStatus: "actions.status.skipped"},
{Status: int(StatusWaiting), StatusName: StatusWaiting.String(), DisplayedStatus: "actions.status.waiting"},
{Status: int(StatusRunning), StatusName: StatusRunning.String(), DisplayedStatus: "actions.status.running"},
{Status: int(StatusBlocked), StatusName: StatusBlocked.String(), DisplayedStatus: "actions.status.blocked"},
{Status: int(StatusCancelling), StatusName: StatusCancelling.String(), DisplayedStatus: "actions.status.cancelling"},
}, statusInfoList)
}
+15
View File
@@ -195,3 +195,18 @@ func HasTwoFactorOrWebAuthn(ctx context.Context, id int64) (bool, error) {
}
return HasWebAuthnRegistrationsByUID(ctx, id)
}
// DisableTwoFactor removes every two-factor method of the given user atomically,
// returning the number of TOTP records and WebAuthn credentials removed.
// It is a no-op for a user that has no 2FA enrolled.
func DisableTwoFactor(ctx context.Context, uid int64) (totp, webAuthn int64, err error) {
err = db.WithTx(ctx, func(ctx context.Context) error {
var e error
if totp, e = db.GetEngine(ctx).Where("uid = ?", uid).Delete(&TwoFactor{}); e != nil {
return e
}
webAuthn, e = db.GetEngine(ctx).Where("user_id = ?", uid).Delete(&WebAuthnCredential{})
return e
})
return totp, webAuthn, err
}
+35
View File
@@ -10,6 +10,7 @@ import (
auth_model "gitea.dev/models/auth"
"gitea.dev/models/unittest"
"github.com/go-webauthn/webauthn/webauthn"
"github.com/pquerna/otp/totp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -45,3 +46,37 @@ func TestTwoFactorValidateAndConsumeTOTP(t *testing.T) {
require.NoError(t, err)
assert.False(t, ok)
}
func TestDisableTwoFactor(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
ctx := t.Context()
const uid = 1000 // a uid with no user/2FA fixtures
// Enroll TOTP and register a WebAuthn credential.
tfa := &auth_model.TwoFactor{UID: uid}
require.NoError(t, tfa.SetSecret("test-secret"))
require.NoError(t, auth_model.NewTwoFactor(ctx, tfa))
_, err := auth_model.CreateCredential(ctx, uid, "test-key", &webauthn.Credential{ID: []byte("test-cred-id")})
require.NoError(t, err)
has, err := auth_model.HasTwoFactorOrWebAuthn(ctx, uid)
require.NoError(t, err)
require.True(t, has)
// Both records are removed and counted separately.
totp, webAuthn, err := auth_model.DisableTwoFactor(ctx, uid)
require.NoError(t, err)
assert.EqualValues(t, 1, totp)
assert.EqualValues(t, 1, webAuthn)
has, err = auth_model.HasTwoFactorOrWebAuthn(ctx, uid)
require.NoError(t, err)
assert.False(t, has)
// A second call on a user without 2FA is a no-op.
totp, webAuthn, err = auth_model.DisableTwoFactor(ctx, uid)
require.NoError(t, err)
assert.EqualValues(t, 0, totp)
assert.EqualValues(t, 0, webAuthn)
}
+15 -10
View File
@@ -55,29 +55,34 @@ func ParseScopedWorkflows(sourceCommit *git.Commit) ([]*ParsedScopedWorkflow, er
return parsed, nil
}
// MatchScopedWorkflows evaluates already-parsed scoped workflows against one consuming event, returning those whose `on:` matches.
// MatchScopedWorkflows evaluates already-parsed scoped workflows against one consuming event.
// It returns the workflows whose `on:` matches, and those that matched the event but were excluded by a branch/paths filter (filtered).
func MatchScopedWorkflows(
parsed []*ParsedScopedWorkflow,
consumerGitRepo *git.Repository,
consumerCommit *git.Commit,
triggedEvent webhook_module.HookEventType,
payload api.Payloader,
) []*DetectedWorkflow {
workflows := make([]*DetectedWorkflow, 0, len(parsed))
) (matched, filtered []*DetectedWorkflow) {
for _, p := range parsed {
for _, evt := range p.Events {
if evt.IsSchedule() {
// schedule is a non-target for scoped workflows
continue
}
if detectMatched(consumerGitRepo, consumerCommit, triggedEvent, payload, evt) {
workflows = append(workflows, &DetectedWorkflow{
EntryName: p.EntryName,
TriggerEvent: evt,
Content: p.Content,
})
dwf := &DetectedWorkflow{
EntryName: p.EntryName,
TriggerEvent: evt,
Content: p.Content,
}
switch detectWorkflowMatch(consumerGitRepo, consumerCommit, triggedEvent, payload, evt) {
case detectMatched:
matched = append(matched, dwf)
case detectFilteredOut:
filtered = append(filtered, dwf)
case detectNotApplicable:
}
}
}
return workflows
return matched, filtered
}
+99 -57
View File
@@ -30,6 +30,14 @@ type DetectedWorkflow struct {
Content []byte
}
type detectResult int
const (
detectMatched detectResult = iota // event matched; run normally
detectNotApplicable // event/type doesn't apply; create nothing
detectFilteredOut // matched but excluded by a branch/paths filter; emits a skipped commit status
)
func init() {
model.OnDecodeNodeError = func(node yaml.Node, out any, err error) {
// Log the error instead of panic or fatal.
@@ -172,18 +180,16 @@ func DetectWorkflows(
triggedEvent webhook_module.HookEventType,
payload api.Payloader,
detectSchedule bool,
) ([]*DetectedWorkflow, []*DetectedWorkflow, error) {
) (workflows, schedules, filtered []*DetectedWorkflow, err error) {
_, entries, err := ListWorkflows(commit)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
workflows := make([]*DetectedWorkflow, 0, len(entries))
schedules := make([]*DetectedWorkflow, 0, len(entries))
for _, entry := range entries {
content, err := GetContentFromEntry(entry)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
// one workflow may have multiple events
@@ -203,18 +209,24 @@ func DetectWorkflows(
}
schedules = append(schedules, dwf)
}
} else if detectMatched(gitRepo, commit, triggedEvent, payload, evt) {
} else {
dwf := &DetectedWorkflow{
EntryName: entry.Name(),
TriggerEvent: evt,
Content: content,
}
workflows = append(workflows, dwf)
switch detectWorkflowMatch(gitRepo, commit, triggedEvent, payload, evt) {
case detectMatched:
workflows = append(workflows, dwf)
case detectFilteredOut:
filtered = append(filtered, dwf)
case detectNotApplicable:
}
}
}
}
return workflows, schedules, nil
return workflows, schedules, filtered, nil
}
func DetectScheduledWorkflows(gitRepo *git.Repository, commit *git.Commit) ([]*DetectedWorkflow, error) {
@@ -252,9 +264,9 @@ func DetectScheduledWorkflows(gitRepo *git.Repository, commit *git.Commit) ([]*D
return wfs, nil
}
func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader, evt *jobparser.Event) bool {
func detectWorkflowMatch(gitRepo *git.Repository, commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader, evt *jobparser.Event) detectResult {
if !canGithubEventMatch(evt.Name, triggedEvent) {
return false
return detectNotApplicable
}
switch triggedEvent {
@@ -268,7 +280,7 @@ func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent web
log.Warn("Ignore unsupported %s event arguments %v", triggedEvent, evt.Acts())
}
// no special filter parameters for these events, just return true if name matched
return true
return detectMatched
case // push
webhook_module.HookEventPush:
@@ -279,14 +291,20 @@ func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent web
webhook_module.HookEventIssueAssign,
webhook_module.HookEventIssueLabel,
webhook_module.HookEventIssueMilestone:
return matchIssuesEvent(payload.(*api.IssuePayload), evt)
if matchIssuesEvent(payload.(*api.IssuePayload), evt) {
return detectMatched
}
return detectNotApplicable
case // issue_comment
webhook_module.HookEventIssueComment,
// `pull_request_comment` is same as `issue_comment`
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_comment-use-issue_comment
webhook_module.HookEventPullRequestComment:
return matchIssueCommentEvent(payload.(*api.IssueCommentPayload), evt)
if matchIssueCommentEvent(payload.(*api.IssueCommentPayload), evt) {
return detectMatched
}
return detectNotApplicable
case // pull_request
webhook_module.HookEventPullRequest,
@@ -300,34 +318,49 @@ func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent web
case // pull_request_review
webhook_module.HookEventPullRequestReviewApproved,
webhook_module.HookEventPullRequestReviewRejected:
return matchPullRequestReviewEvent(payload.(*api.PullRequestPayload), evt)
if matchPullRequestReviewEvent(payload.(*api.PullRequestPayload), evt) {
return detectMatched
}
return detectNotApplicable
case // pull_request_review_comment
webhook_module.HookEventPullRequestReviewComment:
return matchPullRequestReviewCommentEvent(payload.(*api.PullRequestPayload), evt)
if matchPullRequestReviewCommentEvent(payload.(*api.PullRequestPayload), evt) {
return detectMatched
}
return detectNotApplicable
case // release
webhook_module.HookEventRelease:
return matchReleaseEvent(payload.(*api.ReleasePayload), evt)
if matchReleaseEvent(payload.(*api.ReleasePayload), evt) {
return detectMatched
}
return detectNotApplicable
case // registry_package
webhook_module.HookEventPackage:
return matchPackageEvent(payload.(*api.PackagePayload), evt)
if matchPackageEvent(payload.(*api.PackagePayload), evt) {
return detectMatched
}
return detectNotApplicable
case // workflow_run
webhook_module.HookEventWorkflowRun:
return matchWorkflowRunEvent(payload.(*api.WorkflowRunPayload), evt)
if matchWorkflowRunEvent(payload.(*api.WorkflowRunPayload), evt) {
return detectMatched
}
return detectNotApplicable
default:
log.Warn("unsupported event %q", triggedEvent)
return false
return detectNotApplicable
}
}
func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobparser.Event) bool {
func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobparser.Event) detectResult {
// with no special filter parameters
if len(evt.Acts()) == 0 {
return true
return detectMatched
}
matchTimes := 0
@@ -393,14 +426,14 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa
filesChanged, err := commit.GetFilesChangedSinceCommit(pushPayload.Before)
if err != nil {
log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
} else {
patterns, err := workflowpattern.CompilePatterns(vals...)
if err != nil {
break
}
if !workflowpattern.Skip(patterns, filesChanged) {
matchTimes++
}
return detectNotApplicable
}
patterns, err := workflowpattern.CompilePatterns(vals...)
if err != nil {
break
}
if !workflowpattern.Skip(patterns, filesChanged) {
matchTimes++
}
case "paths-ignore":
if refName.IsTag() {
@@ -410,14 +443,14 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa
filesChanged, err := commit.GetFilesChangedSinceCommit(pushPayload.Before)
if err != nil {
log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
} else {
patterns, err := workflowpattern.CompilePatterns(vals...)
if err != nil {
break
}
if !workflowpattern.Filter(patterns, filesChanged) {
matchTimes++
}
return detectNotApplicable
}
patterns, err := workflowpattern.CompilePatterns(vals...)
if err != nil {
break
}
if !workflowpattern.Filter(patterns, filesChanged) {
matchTimes++
}
default:
log.Warn("push event unsupported condition %q", cond)
@@ -427,7 +460,10 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa
if hasBranchFilter && hasTagFilter {
matchTimes++
}
return matchTimes == len(evt.Acts())
if matchTimes == len(evt.Acts()) {
return detectMatched
}
return detectFilteredOut
}
func matchIssuesEvent(issuePayload *api.IssuePayload, evt *jobparser.Event) bool {
@@ -478,7 +514,7 @@ func matchIssuesEvent(issuePayload *api.IssuePayload, evt *jobparser.Event) bool
return matchTimes == len(evt.Acts())
}
func matchPullRequestEvent(gitRepo *git.Repository, commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
func matchPullRequestEvent(gitRepo *git.Repository, commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) detectResult {
acts := evt.Acts()
activityTypeMatched := false
matchTimes := 0
@@ -525,7 +561,7 @@ func matchPullRequestEvent(gitRepo *git.Repository, commit *git.Commit, prPayloa
headCommit, err = gitRepo.GetCommit(prPayload.PullRequest.Head.Sha)
if err != nil {
log.Error("GetCommit [ref: %s]: %v", prPayload.PullRequest.Head.Sha, err)
return false
return detectNotApplicable
}
}
@@ -557,33 +593,39 @@ func matchPullRequestEvent(gitRepo *git.Repository, commit *git.Commit, prPayloa
filesChanged, err := headCommit.GetFilesChangedSinceCommit(prPayload.PullRequest.MergeBase)
if err != nil {
log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", headCommit.ID.String(), err)
} else {
patterns, err := workflowpattern.CompilePatterns(vals...)
if err != nil {
break
}
if !workflowpattern.Skip(patterns, filesChanged) {
matchTimes++
}
return detectNotApplicable
}
patterns, err := workflowpattern.CompilePatterns(vals...)
if err != nil {
break
}
if !workflowpattern.Skip(patterns, filesChanged) {
matchTimes++
}
case "paths-ignore":
filesChanged, err := headCommit.GetFilesChangedSinceCommit(prPayload.PullRequest.MergeBase)
if err != nil {
log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", headCommit.ID.String(), err)
} else {
patterns, err := workflowpattern.CompilePatterns(vals...)
if err != nil {
break
}
if !workflowpattern.Filter(patterns, filesChanged) {
matchTimes++
}
return detectNotApplicable
}
patterns, err := workflowpattern.CompilePatterns(vals...)
if err != nil {
break
}
if !workflowpattern.Filter(patterns, filesChanged) {
matchTimes++
}
default:
log.Warn("pull request event unsupported condition %q", cond)
}
}
return activityTypeMatched && matchTimes == len(evt.Acts())
if !activityTypeMatched {
return detectNotApplicable
}
if matchTimes != len(evt.Acts()) {
return detectFilteredOut
}
return detectMatched
}
func matchIssueCommentEvent(issueCommentPayload *api.IssueCommentPayload, evt *jobparser.Event) bool {
+29 -17
View File
@@ -101,49 +101,49 @@ func TestDetectMatched(t *testing.T) {
triggedEvent webhook_module.HookEventType
payload api.Payloader
yamlOn string
expected bool
expected detectResult
}{
{
desc: "HookEventCreate(create) matches GithubEventCreate(create)",
triggedEvent: webhook_module.HookEventCreate,
payload: nil,
yamlOn: "on: create",
expected: true,
expected: detectMatched,
},
{
desc: "HookEventIssues(issues) `opened` action matches GithubEventIssues(issues)",
triggedEvent: webhook_module.HookEventIssues,
payload: &api.IssuePayload{Action: api.HookIssueOpened},
yamlOn: "on: issues",
expected: true,
expected: detectMatched,
},
{
desc: "HookEventIssues(issues) `milestoned` action matches GithubEventIssues(issues)",
triggedEvent: webhook_module.HookEventIssues,
payload: &api.IssuePayload{Action: api.HookIssueMilestoned},
yamlOn: "on: issues",
expected: true,
expected: detectMatched,
},
{
desc: "HookEventPullRequestSync(pull_request_sync) matches GithubEventPullRequest(pull_request)",
triggedEvent: webhook_module.HookEventPullRequestSync,
payload: &api.PullRequestPayload{Action: api.HookIssueSynchronized},
yamlOn: "on: pull_request",
expected: true,
expected: detectMatched,
},
{
desc: "HookEventPullRequest(pull_request) `label_updated` action doesn't match GithubEventPullRequest(pull_request) with no activity type",
triggedEvent: webhook_module.HookEventPullRequest,
payload: &api.PullRequestPayload{Action: api.HookIssueLabelUpdated},
yamlOn: "on: pull_request",
expected: false,
expected: detectNotApplicable,
},
{
desc: "HookEventPullRequest(pull_request) `closed` action doesn't match GithubEventPullRequest(pull_request) with no activity type",
triggedEvent: webhook_module.HookEventPullRequest,
payload: &api.PullRequestPayload{Action: api.HookIssueClosed},
yamlOn: "on: pull_request",
expected: false,
expected: detectNotApplicable,
},
{
desc: "HookEventPullRequest(pull_request) `closed` action doesn't match GithubEventPullRequest(pull_request) with branches",
@@ -155,56 +155,56 @@ func TestDetectMatched(t *testing.T) {
},
},
yamlOn: "on:\n pull_request:\n branches: [main]",
expected: false,
expected: detectNotApplicable,
},
{
desc: "HookEventPullRequest(pull_request) `label_updated` action matches GithubEventPullRequest(pull_request) with `label` activity type",
triggedEvent: webhook_module.HookEventPullRequest,
payload: &api.PullRequestPayload{Action: api.HookIssueLabelUpdated},
yamlOn: "on:\n pull_request:\n types: [labeled]",
expected: true,
expected: detectMatched,
},
{
desc: "HookEventPullRequestReviewComment(pull_request_review_comment) matches GithubEventPullRequestReviewComment(pull_request_review_comment)",
triggedEvent: webhook_module.HookEventPullRequestReviewComment,
payload: &api.PullRequestPayload{Action: api.HookIssueReviewed},
yamlOn: "on:\n pull_request_review_comment:\n types: [created]",
expected: true,
expected: detectMatched,
},
{
desc: "HookEventPullRequestReviewRejected(pull_request_review_rejected) doesn't match GithubEventPullRequestReview(pull_request_review) with `dismissed` activity type (we don't support `dismissed` at present)",
triggedEvent: webhook_module.HookEventPullRequestReviewRejected,
payload: &api.PullRequestPayload{Action: api.HookIssueReviewed},
yamlOn: "on:\n pull_request_review:\n types: [dismissed]",
expected: false,
expected: detectNotApplicable,
},
{
desc: "HookEventRelease(release) `published` action matches GithubEventRelease(release) with `published` activity type",
triggedEvent: webhook_module.HookEventRelease,
payload: &api.ReleasePayload{Action: api.HookReleasePublished},
yamlOn: "on:\n release:\n types: [published]",
expected: true,
expected: detectMatched,
},
{
desc: "HookEventPackage(package) `created` action doesn't match GithubEventRegistryPackage(registry_package) with `updated` activity type",
triggedEvent: webhook_module.HookEventPackage,
payload: &api.PackagePayload{Action: api.HookPackageCreated},
yamlOn: "on:\n registry_package:\n types: [updated]",
expected: false,
expected: detectNotApplicable,
},
{
desc: "HookEventWiki(wiki) matches GithubEventGollum(gollum)",
triggedEvent: webhook_module.HookEventWiki,
payload: nil,
yamlOn: "on: gollum",
expected: true,
expected: detectMatched,
},
{
desc: "HookEventSchedule(schedule) matches GithubEventSchedule(schedule)",
triggedEvent: webhook_module.HookEventSchedule,
payload: nil,
yamlOn: "on: schedule",
expected: true,
expected: detectMatched,
},
{
desc: "push to tag matches workflow with paths condition (should skip paths check)",
@@ -222,7 +222,19 @@ func TestDetectMatched(t *testing.T) {
},
commit: nil,
yamlOn: "on:\n push:\n paths:\n - src/**",
expected: true,
expected: detectMatched,
},
{
desc: "push branch filter excludes -> filtered out",
triggedEvent: webhook_module.HookEventPush,
payload: &api.PushPayload{
Ref: "refs/heads/feature/x",
Before: "0000000",
Commits: []*api.PayloadCommit{{ID: "abc", Added: []string{"a.go"}, Message: "x"}},
},
commit: nil,
yamlOn: "on:\n push:\n branches: [main]",
expected: detectFilteredOut,
},
}
@@ -231,7 +243,7 @@ func TestDetectMatched(t *testing.T) {
evts, err := GetEventsFromContent(fullWorkflowContent(tc.yamlOn))
assert.NoError(t, err)
assert.Len(t, evts, 1)
assert.Equal(t, tc.expected, detectMatched(nil, tc.commit, tc.triggedEvent, tc.payload, evts[0]))
assert.Equal(t, tc.expected, detectWorkflowMatch(nil, tc.commit, tc.triggedEvent, tc.payload, evts[0]))
})
}
}
+13 -13
View File
@@ -21,19 +21,6 @@ func TestCommitsCount(t *testing.T) {
assert.Equal(t, int64(3), commitsCount)
}
func TestCommitsCountWithoutBase(t *testing.T) {
bareRepo1 := &mockRepository{path: "repo1_bare"}
commitsCount, err := CommitsCount(t.Context(), bareRepo1,
CommitsCountOptions{
Not: "master",
Revision: []string{"branch1"},
})
assert.NoError(t, err)
assert.Equal(t, int64(2), commitsCount)
}
func TestCommitsCountWithSinceUntil(t *testing.T) {
bareRepo1 := &mockRepository{path: "repo1_bare"}
revision := []string{"8006ff9adbf0cb94da7dad9e537e53817f9fa5c0"}
@@ -65,6 +52,19 @@ func TestCommitsCountWithSinceUntil(t *testing.T) {
}
}
func TestCommitsCountWithoutBase(t *testing.T) {
bareRepo1 := &mockRepository{path: "repo1_bare"}
commitsCount, err := CommitsCount(t.Context(), bareRepo1,
CommitsCountOptions{
Not: "master",
Revision: []string{"branch1"},
})
assert.NoError(t, err)
assert.Equal(t, int64(2), commitsCount)
}
func TestGetLatestCommitTime(t *testing.T) {
bareRepo1 := &mockRepository{path: "repo1_bare"}
lct, err := GetLatestCommitTime(t.Context(), bareRepo1)
+1 -1
View File
@@ -54,7 +54,7 @@ func (st *Sanitizer) createDefaultPolicy() *bluemonday.Policy {
// Allow 'color' and 'background-color' properties for the style attribute on text elements.
policy.AllowStyles("color", "background-color").OnElements("div", "span", "p", "tr", "th", "td")
policy.AllowAttrs("src", "autoplay", "controls").OnElements("video")
policy.AllowAttrs("src", "autoplay", "controls", "muted", "loop", "playsinline").OnElements("video")
// Native support of "<picture><source media=... srcset=...><img src=...></picture>"
// ATTENTION: it only works with "auto" theme, because "media" query doesn't work with the theme chosen by end user manually.
-1
View File
@@ -19,7 +19,6 @@ type CreateUserOption struct {
// The full display name of the user
FullName string `json:"full_name" binding:"MaxSize(100)"`
// required: true
// swagger:strfmt email
Email string `json:"email" binding:"Required;Email;MaxSize(254)"`
// The plain text password for the user
Password string `json:"password" binding:"MaxSize(255)"`
-1
View File
@@ -133,7 +133,6 @@ type IssueAssigneesOption struct {
// EditDeadlineOption options for creating a deadline
type EditDeadlineOption struct {
// required:true
// swagger:strfmt date-time
Deadline *time.Time `json:"due_date"`
}
+2 -2
View File
@@ -54,10 +54,10 @@ type CreateTeamOption struct {
// Whether the team has access to all repositories in the organization
IncludesAllRepositories bool `json:"includes_all_repositories"`
Permission RepoWritePermission `json:"permission"`
// example: ["repo.actions","repo.code","repo.issues","repo.ext_issues","repo.wiki","repo.ext_wiki","repo.pulls","repo.releases","repo.projects","repo.ext_wiki"]
// example: ["repo.actions","repo.packages","repo.code","repo.issues","repo.ext_issues","repo.wiki","repo.pulls","repo.releases","repo.projects","repo.ext_wiki"]
// Deprecated: This variable should be replaced by UnitsMap and will be dropped in later versions.
Units []string `json:"units"`
// example: {"repo.actions","repo.packages","repo.code":"read","repo.issues":"write","repo.ext_issues":"none","repo.wiki":"admin","repo.pulls":"owner","repo.releases":"none","repo.projects":"none","repo.ext_wiki":"none"}
// example: {"repo.actions":"read","repo.packages":"read","repo.code":"read","repo.issues":"write","repo.ext_issues":"none","repo.wiki":"admin","repo.pulls":"owner","repo.releases":"none","repo.projects":"none","repo.ext_wiki":"none"}
UnitsMap map[string]string `json:"units_map"`
// Whether the team can create repositories in the organization
CanCreateOrgRepo bool `json:"can_create_org_repo"`
+32 -5
View File
@@ -74,7 +74,7 @@
"forks": "Forks",
"activities": "Aktivitäten",
"pull_requests": "Pull-Requests",
"issues": "Probleme",
"issues": "Issues",
"milestones": "Meilensteine",
"ok": "OK",
"cancel": "Abbrechen",
@@ -1101,7 +1101,7 @@
"repo.migrate_items_wiki": "Wiki",
"repo.migrate_items_milestones": "Meilensteine",
"repo.migrate_items_labels": "Labels",
"repo.migrate_items_issues": "Probleme",
"repo.migrate_items_issues": "Issues",
"repo.migrate_items_pullrequests": "Pull-Requests",
"repo.migrate_items_merge_requests": "Merge-Requests",
"repo.migrate_items_releases": "Veröffentlichungen",
@@ -1178,7 +1178,7 @@
"repo.find_tag": "Tag finden",
"repo.branches": "Branches",
"repo.tags": "Tags",
"repo.issues": "Probleme",
"repo.issues": "Issues",
"repo.pulls": "Pull-Requests",
"repo.projects": "Projekte",
"repo.packages": "Pakete",
@@ -2300,7 +2300,7 @@
"repo.settings.event_repository": "Repository",
"repo.settings.event_repository_desc": "Repository erstellt oder gelöscht.",
"repo.settings.event_header_issue": "Issue Ereignisse",
"repo.settings.event_issues": "Probleme",
"repo.settings.event_issues": "Issues",
"repo.settings.event_issues_desc": "Issue geöffnet, geschlossen, wieder geöffnet, bearbeitet oder gelöscht.",
"repo.settings.event_issue_assign": "Issue zugewiesen",
"repo.settings.event_issue_assign_desc": "Issue zugewiesen oder Zuweisung entfernt.",
@@ -3104,7 +3104,7 @@
"admin.repos.owner": "Besitzer",
"admin.repos.name": "Name",
"admin.repos.private": "Privat",
"admin.repos.issues": "Probleme",
"admin.repos.issues": "Issues",
"admin.repos.size": "Größe",
"admin.repos.lfs_size": "LFS-Größe",
"admin.packages.package_manage_panel": "Paketverwaltung",
@@ -3779,6 +3779,7 @@
"actions.runs.commit": "Commit",
"actions.runs.run_details": "Run Details",
"actions.runs.workflow_file": "Workflow-Datei",
"actions.runs.workflow_file_no_permission": "Keine Berechtigung zum Anzeigen der Workflow-Datei",
"actions.runs.scheduled": "Geplant",
"actions.runs.pushed_by": "gepusht von",
"actions.runs.invalid_workflow_helper": "Die Workflow-Konfigurationsdatei ist ungültig. Bitte überprüfe Deine Konfigurationsdatei: %s",
@@ -3835,7 +3836,33 @@
"actions.workflow.scope_owner": "Besitzer",
"actions.workflow.scope_global": "Global",
"actions.workflow.required": "Erforderlich",
"actions.workflow.scoped_required_cannot_disable": "Dieser Scoped Workflow ist erforderlich und kann nicht deaktiviert werden.",
"actions.scoped_workflows": "Scoped Workflows",
"actions.scoped_workflows.desc_org": "Repositories als Scoped Workflow Quellen registrieren. Workflow-Dateien unter den Workflow-Verzeichnissen eines Quell-Repositorys laufen in jedem Projektarchiv dieser Organisation, im eigenen Kontext des Projektarchivs.",
"actions.scoped_workflows.desc_user": "Repositories als Scoped Workflow Quellen registrieren. Workflow-Dateien unter den Workflow-Verzeichnissen eines Quell-Repositorys laufen in jedem Projektarchiv dieser Organisation, im eigenen Kontext des Projektarchivs.",
"actions.scoped_workflows.desc_global": "Repositories als Scoped Workflow-Quellen registrieren. Workflow-Dateien unter den Workflow-Verzeichnissen eines Quellcode-Repositorys laufen auf jedem Projektarchiv in dieser Instanz im eigenen Kontext des Projektarchivs. Da Quellen auf Instanzenebene auf den Ereignissen jedes Projektarchivs ausgewertet werden, kann die Registrierung bei großen Instanzen Overhead hinzufügen.",
"actions.scoped_workflows.add_help": "Um Scoped Workflows aus einem Repository zu erstellen, übertrage die Workflow-Dateien unter <code>%s</code> in seinem Standard Branch, dann registrieren Sie das Projektarchiv als Quelle unten.",
"actions.scoped_workflows.security_note": "Der Workflow-Inhalt eines Quell-Repositorys wird in jedem Repository ausgeführt, für das er gilt. Die Skripte der einzelnen Schritte sowie deren Ausgabe werden in den Actions-Logs des jeweiligen Repositorys gespeichert und sind für alle sichtbar, die die Actions des konsumierenden Repositorys einsehen können. Das Registrieren eines privaten Repositorys als Quelle legt daher dessen Workflow-Logik über diese Logs offen. Registriere nur Repositorys, deren Workflow-Inhalte mit allen konsumierenden Repositorys geteilt werden dürfen. Wenn ein scoped Workflow einen wiederverwendbaren Workflow aus einem privaten Repository referenziert, stelle sicher, dass jedes konsumierende Repository darauf Lesezugriff hat andernfalls schlägt der Workflow dort fehl.",
"actions.scoped_workflows.source.add": "Quell-Repository hinzufügen",
"actions.scoped_workflows.source.add_success": "Quell-Repository hinzugefügt.",
"actions.scoped_workflows.source.remove_success": "Quell-Repository entfernt.",
"actions.scoped_workflows.source.not_found": "Repository nicht gefunden.",
"actions.scoped_workflows.required.update_success": "Erforderliche Workflows aktualisiert.",
"actions.scoped_workflows.required.label": "Workflows als erforderlich markieren (ein erforderlicher Workflow kann nicht durch Repositories deaktiviert werden):",
"actions.scoped_workflows.required.patterns": "Erforderliche Statusüberprüfungsmuster",
"actions.scoped_workflows.required.patterns_aria": "Erforderliche Statusüberprüfungsmuster für %s",
"actions.scoped_workflows.required.patterns_note": "nur erzwungen während der Workflow benötigt wird",
"actions.scoped_workflows.required.patterns_hint": "Markieren Sie den Workflow als erforderlich, um seine Statusüberprüfungsmuster zu konfigurieren.",
"actions.scoped_workflows.required.patterns_help": "Ein Statusüberprüfungsmuster (glob) pro Zeile. Ein Pull-Request kann erst zusammengeführt werden, wenn ein Status mit jedem Muster übereinstimmt. Dies wird für jeden Zielzweig erzwungen, der eine Schutzregel hat, auch für einen mit einer eigenen Statusüberprüfung; ein Zielzweig ohne Schutzregel ist nicht ausgeschaltet.",
"actions.scoped_workflows.required.patterns_empty": "Jeder benötigte Workflow benötigt mindestens ein Statusüberprüfungsmuster.",
"actions.scoped_workflows.required.missing_file": "nicht mehr im Quelltext",
"actions.scoped_workflows.required.expected_contexts": "Erwartete Statusüberprüfung (eine Prüfung, die zu einem Muster passt)",
"actions.scoped_workflows.required.no_status_contexts": "Dieser Workflow postet keine Status Checks, ihn als Anforderung zu markieren würde jede Pull Request blockieren. Deaktiviere die Anforderung.",
"actions.scoped_workflows.no_files": "Im Standard-Branch wurden keine Scoped Workflow-Dateien gefunden.",
"actions.workflow.run": "Workflow ausführen",
"actions.workflow.create_status_badge": "Status Badge erstellen",
"actions.workflow.status_badge": "Status Badge",
"actions.workflow.status_badge_url": "Badge-URL",
"actions.workflow.not_found": "Workflow '%s' wurde nicht gefunden.",
"actions.workflow.run_success": "Workflow '%s' erfolgreich ausgeführt.",
"actions.workflow.from_ref": "Nutze Workflow von",
+121 -77
View File
@@ -80,8 +80,8 @@
"cancel": "Annuler",
"retry": "Réessayez",
"rerun": "Relancer",
"rerun_all": "Relancer toutes les tâches",
"rerun_failed": "Relancer les tâches échouées",
"rerun_all": "Relancer toutes les missions.",
"rerun_failed": "Relancer les missions échouées.",
"save": "Enregistrer",
"add": "Ajouter",
"add_all": "Tout Ajouter",
@@ -505,10 +505,10 @@
"mail.repo.actions.run.failed": "Lexécution a échoué",
"mail.repo.actions.run.succeeded": "Lexécution a réussi",
"mail.repo.actions.run.cancelled": "Lexécution a été annulée",
"mail.repo.actions.jobs.all_succeeded": "Tous les tâches ont réussi.",
"mail.repo.actions.jobs.all_failed": "Toutes les tâches ont échoué.",
"mail.repo.actions.jobs.some_not_successful": "Certaines tâches nont pas réussi.",
"mail.repo.actions.jobs.all_cancelled": "Toutes les tâches ont bien été annulés.",
"mail.repo.actions.jobs.all_succeeded": "Tous les missions ont réussi.",
"mail.repo.actions.jobs.all_failed": "Toutes les missions ont échoué.",
"mail.repo.actions.jobs.some_not_successful": "Certaines missions nont pas réussi.",
"mail.repo.actions.jobs.all_cancelled": "Toutes les missions ont bien été annulées.",
"mail.team_invite.subject": "%[1]s vous a invité à rejoindre lorganisation %[2]s",
"mail.team_invite.text_1": "%[1]s vous a invité à rejoindre l’équipe %[2]s dans lorganisation %[3]s.",
"mail.team_invite.text_2": "Veuillez cliquer sur le lien suivant pour rejoindre l'équipe :",
@@ -944,8 +944,8 @@
"settings.email_notifications.disable": "Ne pas notifier",
"settings.email_notifications.submit": "Définir les préférences de courriel",
"settings.email_notifications.andyourown": "Inclure vos propres notifications",
"settings.email_notifications.actions.desc": "Notification pour les executions de workflows sur les dépôts configurés avec les <a target=\"_blank\" href=\"%s\">Actions Gitea</a>.",
"settings.email_notifications.actions.failure_only": "Ne notifier que pour les exécutions échouées",
"settings.email_notifications.actions.desc": "Notifier les procédures des dépôts configurés avec les <a target=\"_blank\" href=\"%s\">Actions Gitea</a>.",
"settings.email_notifications.actions.failure_only": "Ne notifier que procédures échouées",
"settings.visibility": "Visibilité de l'utilisateur",
"settings.visibility.public": "Publique",
"settings.visibility.public_tooltip": "Visible par tout le monde",
@@ -1321,6 +1321,7 @@
"repo.editor.fork_branch_exists": "La branche « %s » existe déjà dans votre bifurcation, veuillez choisir un nouveau nom.",
"repo.commits.desc": "Naviguer dans l'historique des modifications.",
"repo.commits.commits": "Révisions",
"repo.commits.history_enable_follow_renames": "Inclure les renommages",
"repo.commits.no_commits": "Pas de révisions en commun. \"%s\" et \"%s\" ont des historiques entièrement différents.",
"repo.commits.nothing_to_compare": "Ces révisions sont équivalentes.",
"repo.commits.search.tooltip": "Vous pouvez utiliser les mots-clés \"author:\", \"committer:\", \"after:\", ou \"before:\" pour filtrer votre recherche, ex.: \"revert author:Alice before:2019-01-13\".",
@@ -1332,8 +1333,8 @@
"repo.commits.older": "Précédemment",
"repo.commits.newer": "Récemment",
"repo.commits.signed_by": "Signé par",
"repo.commits.signed_by_untrusted_user": "Signature provenant d'un utilisateur dilletant",
"repo.commits.signed_by_untrusted_user_unmatched": "Signature discordante de l'auteur de la révision et provenant d'un utilisateur dilletant",
"repo.commits.signed_by_untrusted_user": "Signé en dilettante par",
"repo.commits.signed_by_untrusted_user_unmatched": "Signé, sans en être lauteur, par",
"repo.commits.gpg_key_id": "ID de la clé GPG",
"repo.commits.ssh_key_fingerprint": "Empreinte numérique de la clé SSH",
"repo.commits.view_path": "Voir à ce point de l'historique",
@@ -1817,9 +1818,9 @@
"repo.pulls.is_checking": "Recherche de conflits de fusion…",
"repo.pulls.is_ancestor": "Cette branche est déjà présente dans la branche ciblée. Il n'y a rien à fusionner.",
"repo.pulls.is_empty": "Les changements sur cette branche sont déjà sur la branche cible. Cette révision sera vide.",
"repo.pulls.required_status_check_failed": "Certains contrôles requis n'ont pas réussi.",
"repo.pulls.required_status_check_missing": "Certains contrôles requis sont manquants.",
"repo.pulls.required_status_check_administrator": "En tant qu'administrateur, vous pouvez toujours fusionner cette requête de pull.",
"repo.pulls.required_status_check_failed": "Certains signaux requis n'ont pas réussi.",
"repo.pulls.required_status_check_missing": "Certains signaux requis sont manquants.",
"repo.pulls.required_status_check_administrator": "En tant quadministrateur, vous pouvez fusionner cette demande dajout.",
"repo.pulls.required_status_check_bypass_allowlist": "Vous êtes autorisé à contourner les règles de protection pour cette fusion.",
"repo.pulls.blocked_by_approvals": "Cette demande dajout nest pas suffisamment approuvée. %d approbations obtenues sur %d.",
"repo.pulls.blocked_by_approvals_whitelisted": "Cette demande dajout na pas encore assez dapprobations. %d sur %d approbations de la part des utilisateurs ou équipes sur la liste autorisée.",
@@ -1843,7 +1844,7 @@
"repo.pulls.no_merge_desc": "Cette demande dajout ne peut être fusionnée car toutes les options de fusion du dépôt sont désactivées.",
"repo.pulls.no_merge_helper": "Activez des options de fusion dans les paramètres du dépôt ou fusionnez la demande manuellement.",
"repo.pulls.no_merge_wip": "Cette demande dajout ne peut pas être fusionnée car elle est marquée en chantier.",
"repo.pulls.no_merge_not_ready": "Cette demande dajout nest pas prête à être fusionnée, vérifiez les évaluations et le contrôle qualité.",
"repo.pulls.no_merge_not_ready": "Cette demande dajout nest pas prête à être fusionnée, vérifiez les évaluations et les signaux.",
"repo.pulls.no_merge_access": "Vous n'êtes pas autorisé⋅e à fusionner cette demande d'ajout.",
"repo.pulls.merge_pull_request": "Créer une révision de fusion",
"repo.pulls.rebase_merge_pull_request": "Rebaser puis rattraper",
@@ -1867,19 +1868,19 @@
"repo.pulls.push_rejected_summary": "Message de rejet complet",
"repo.pulls.push_rejected_no_message": "Échec de la fusion : la soumission a été rejetée sans raison. Contrôler les déclencheurs Git pour ce dépôt.",
"repo.pulls.open_unmerged_pull_exists": "Vous ne pouvez pas rouvrir ceci car la demande dajout #%d, en attente, a des propriétés identiques.",
"repo.pulls.status_checking": "Certains contrôles sont en attente",
"repo.pulls.status_checks_success": "Tous les contrôles ont réussi",
"repo.pulls.status_checks_warning": "Quelques vérifications ont signalé des avertissements",
"repo.pulls.status_checks_failure_required": "Des vérifications obligatoires ont échoué",
"repo.pulls.status_checks_failure_optional": "Des vérifications optionnelles ont échoué",
"repo.pulls.status_checks_error": "Quelques vérifications ont signalé des erreurs",
"repo.pulls.status_checking": "Certains signaux sont en attente",
"repo.pulls.status_checks_success": "Tous les signaux ont réussi",
"repo.pulls.status_checks_warning": "Des signaux déclarent des avertissements",
"repo.pulls.status_checks_failure_required": "Des signaux requis ont échoués",
"repo.pulls.status_checks_failure_optional": "Des signaux optionnels ont échoués",
"repo.pulls.status_checks_error": "Des signaux rapportent des erreurs",
"repo.pulls.status_checks_requested": "Requis",
"repo.pulls.status_checks_details": "Détails",
"repo.pulls.status_checks_hide_all": "Masquer toutes les vérifications",
"repo.pulls.status_checks_hide_all": "Masquer les signaux",
"repo.pulls.status_checks_show_all": "Afficher toutes les vérifications",
"repo.pulls.status_checks_approve_all": "Accepter tous les flux de travail",
"repo.pulls.status_checks_need_approvals": "%d flux de travail en attente dapprobation",
"repo.pulls.status_checks_need_approvals_helper": "Ce flux de travail ne sexécutera quaprès lapprobation par le mainteneur du dépôt.",
"repo.pulls.status_checks_approve_all": "Approuver toutes les procédures",
"repo.pulls.status_checks_need_approvals": "%d procédure(s) en attente dapprobation",
"repo.pulls.status_checks_need_approvals_helper": "Cette procédure ne sexecutera quaprès lapprobation par le mainteneur du dépôt.",
"repo.pulls.update_branch": "Actualiser la branche par fusion",
"repo.pulls.update_branch_rebase": "Actualiser la branche par rebasage",
"repo.pulls.update_branch_success": "La mise à jour de la branche a réussi",
@@ -2201,11 +2202,13 @@
"repo.settings.trust_model.default.desc": "Utiliser le niveau de confiance configuré par défaut pour cette instance Gitea.",
"repo.settings.trust_model.collaborator": "Collaborateur",
"repo.settings.trust_model.collaborator.long": "Collaborateur : ne se fier qu'aux signatures des collaborateurs du dépôt",
"repo.settings.trust_model.collaborator.desc": "La signature dune révision est dite « fiable » si elle correspond à un collaborateur du dépôt, indépendamment de son auteur. À défaut, si elle correspond à lauteur de la révision, elle sera « dilettante », et « discordante » sinon.",
"repo.settings.trust_model.collaborator.desc": "Une révision est réputée authentifiée si elle est signée par un collaborateur du dépôt. Si elle nest que signée par son auteur, elle sera réputée dilettante, et discordante sinon.",
"repo.settings.trust_model.committer": "Auteur",
"repo.settings.trust_model.committer.long": "Auteur : ne se fier quaux signatures des auteurs des révisions (mimique GitHub en forçant Gitea à co-signer ses révisions).",
"repo.settings.trust_model.committer.desc": "Une révision est réputée authentifiée si elle est signée par son auteur, et discordante si les signatures diffèrent. Cela force Gitea à signer ses propres révisions en créditant lauteur original en pied de révision \"Co-authored-by:\" et \"Co-committed-by:\". La clé par défaut de Gitea doit correspondre à celle dun utilisateur existant.",
"repo.settings.trust_model.collaboratorcommitter": "Collaborateur et Auteur",
"repo.settings.trust_model.collaboratorcommitter.long": "Collaborateur et Auteur : ne se fier qu'aux signatures des auteurs collaborant au dépôt",
"repo.settings.trust_model.collaboratorcommitter.desc": "Une révision est réputée authentifiée si est elle signée par son auteur étant lui-même collaborateur du dépôt. Si elle nest que signée par son auteur, elle sera réputée dilettante, et discordante sinon. Cela force Gitea à signer ses propres révisions en créditant lauteur original en pied de révision \"Co-authored-by:\". La clé par défaut de Gitea doit correspondre à celle dun utilisateur existant.",
"repo.settings.wiki_delete": "Supprimer les données du Wiki",
"repo.settings.wiki_delete_desc": "Supprimer les données du wiki d'un dépôt est permanent. Cette action est irréversible.",
"repo.settings.wiki_delete_notices_1": "- Ceci supprimera de manière permanente et désactivera le wiki de dépôt pour %s.",
@@ -2326,11 +2329,11 @@
"repo.settings.event_pull_request_review_request_desc": "Création ou suppresion de demandes d’évaluation.",
"repo.settings.event_pull_request_approvals": "Approbations de demande d'ajout",
"repo.settings.event_pull_request_merge": "Fusion de demande d'ajout",
"repo.settings.event_header_workflow": "Événements du flux de travail",
"repo.settings.event_workflow_run": "Exécution du flux de travail",
"repo.settings.event_workflow_run_desc": "Tâche du flux de travail Gitea Actions ajoutée, en attente, en cours ou terminée.",
"repo.settings.event_workflow_job": "Tâches du flux de travail",
"repo.settings.event_workflow_job_desc": "Tâches du flux de travail Gitea Actions en file dattente, en attente, en cours ou terminée.",
"repo.settings.event_header_workflow": "Événements de procédure",
"repo.settings.event_workflow_run": "Exécution de procédure",
"repo.settings.event_workflow_run_desc": "Exécution des procédures des Actions Gitea ajoutée, en attente, en cours ou terminées.",
"repo.settings.event_workflow_job": "Missions des procédures",
"repo.settings.event_workflow_job_desc": "Les missions ajoutées, en attente, en cours ou terminées de la procédure des Actions Gitea.",
"repo.settings.event_package": "Paquet",
"repo.settings.event_package_desc": "Paquet créé ou supprimé.",
"repo.settings.branch_filter": "Filtre de branche",
@@ -2417,17 +2420,17 @@
"repo.settings.protect_merge_whitelist_teams": "Équipes autorisées à fusionner :",
"repo.settings.protect_bypass_allowlist": "Contourner la protection de la branche",
"repo.settings.protect_enable_bypass_allowlist": "Autoriser des utilisateurs et des équipes à contourner les restrictions de branche",
"repo.settings.protect_enable_bypass_allowlist_desc": "Les utilisateurs ou équipes autorisés peuvent fusionner ou pousser des changements nonobstant les règles dapprobations, de vérifications de statut et les protections fichiers.",
"repo.settings.protect_enable_bypass_allowlist_desc": "Les utilisateurs ou équipes autorisés peuvent fusionner ou pousser des changements nonobstant les règles dapprobations, de vérifications des signaux et les protections de fichiers.",
"repo.settings.protect_bypass_allowlist_users": "Liste dutilisateurs autorisés à contourner les protections :",
"repo.settings.protect_bypass_allowlist_teams": "Liste d’équipes autorisées à contourner les protections :",
"repo.settings.protect_check_status_contexts": "Activer le Contrôle Qualité",
"repo.settings.protect_status_check_patterns": "Motifs de vérification des statuts :",
"repo.settings.protect_status_check_patterns_desc": "Entrez des motifs pour spécifier quelles vérifications doivent réussir avant que des branches puissent être fusionnées. Un motif par ligne. Un motif ne peut être vide.",
"repo.settings.protect_check_status_contexts": "Activer les signaux",
"repo.settings.protect_status_check_patterns": "Motifs de signal :",
"repo.settings.protect_status_check_patterns_desc": "Entrez des motifs pour spécifier quelles signaux doivent réussir avant que des branches puissent être fusionnées. Un motif par ligne. Un motif ne peut être vide.",
"repo.settings.protect_check_status_contexts_desc": "Exiger le status « succès » avant de fusionner. Quand activée, une branche protégée ne peux accepter que des soumissions ou des fusions ayant le status « succès ». Lorsqu'il ny a pas de contexte, la dernière révision fait foi.",
"repo.settings.protect_check_status_contexts_list": "Contrôles qualité trouvés au cours de la semaine dernière pour ce dépôt",
"repo.settings.protect_check_status_contexts_list": "Signaux trouvés au cours de la semaine passée pour ce dépôt",
"repo.settings.protect_status_check_matched": "Correspondant",
"repo.settings.protect_invalid_status_check_pattern": "Motif de vérification des statuts incorrect : « %s ».",
"repo.settings.protect_no_valid_status_check_patterns": "Aucun motif de vérification des statuts valide.",
"repo.settings.protect_invalid_status_check_pattern": "Motif de signal invalide : « %s ».",
"repo.settings.protect_no_valid_status_check_patterns": "Aucun motif de signaux valide.",
"repo.settings.protect_required_approvals": "Minimum d'approbations requis :",
"repo.settings.protect_required_approvals_desc": "Permet de fusionner les demandes dajout lorsque suffisamment d’évaluation sont positives.",
"repo.settings.protect_approvals_whitelist_enabled": "Restreindre les approbations sur autorisation uniquement",
@@ -2597,6 +2600,7 @@
"repo.diff.review.self_approve": "Les auteurs dune demande dajout ne peuvent pas approuver leur propre demande dajout",
"repo.diff.committed_by": "révisé par",
"repo.commits.avatar_stack_and": "et",
"repo.commits.avatar_stack_people": "%d personne(s)",
"repo.diff.protected": "Protégé",
"repo.diff.image.side_by_side": "Côte à côte",
"repo.diff.image.swipe": "Glisser",
@@ -2724,6 +2728,7 @@
"graphs.code_frequency.what": "fréquence du code",
"graphs.contributors.what": "contributions",
"graphs.recent_commits.what": "révisions récentes",
"graphs.chart_zoom_hint": "Glisser : zoom, Maj + Glisser : pano, Double-clic : recentrer",
"org.org_name_holder": "Nom de l'organisation",
"org.org_full_name_holder": "Nom complet de l'organisation",
"org.org_name_helper": "Le nom de l'organisation doit être court et mémorable.",
@@ -3008,7 +3013,7 @@
"admin.dashboard.gc_lfs": "Purger les métaobjets LFS",
"admin.dashboard.stop_zombie_tasks": "Arrêter les tâches zombies",
"admin.dashboard.stop_endless_tasks": "Arrêter les tâches interminables",
"admin.dashboard.cancel_abandoned_jobs": "Annuler les actions des tâches abandonnés",
"admin.dashboard.cancel_abandoned_jobs": "Annuler les actions des missions abandonnées",
"admin.dashboard.start_schedule_tasks": "Démarrer les tâches planifiées",
"admin.dashboard.sync_branch.started": "Début de la synchronisation des branches",
"admin.dashboard.sync_tag.started": "Synchronisation des étiquettes",
@@ -3755,7 +3760,7 @@
"actions.runners.delete_runner_success": "Exécuteur supprimé avec succès",
"actions.runners.delete_runner_failed": "Impossible de supprimer l'Exécuteur",
"actions.runners.delete_runner_header": "Êtes-vous sûr de vouloir supprimer cet exécuteur ?",
"actions.runners.delete_runner_notice": "Si une tâche est en cours sur cet exécuteur, elle sera terminée et marquée comme échouée. Cela risque dinterrompre le flux de travail.",
"actions.runners.delete_runner_notice": "Si une tâche est en cours sur cet exécuteur, elle sera interrompue et marquée comme échouée. Cela pourrait interrompre sa procédure.",
"actions.runners.none": "Aucun exécuteur disponible",
"actions.runners.status.unspecified": "Inconnu",
"actions.runners.status.idle": "Inactif",
@@ -3765,20 +3770,22 @@
"actions.runners.reset_registration_token": "Réinitialiser le jeton d'enregistrement",
"actions.runners.reset_registration_token_confirm": "Voulez-vous révoquer le jeton actuel et en générer un nouveau ?",
"actions.runners.reset_registration_token_success": "Le jeton dinscription de lexécuteur a été réinitialisé avec succès",
"actions.runs.all_workflows": "Tous les flux de travail",
"actions.runs.other_workflows": "Autres flux de travail",
"actions.runs.other_workflows_tooltip": "Les flux de travail qui ont été exécutés dans ce dépôt mais qui nexistent pas dans la branche par défaut.",
"actions.runs.workflow_run_count_1": "%d exécution du workflow",
"actions.runs.workflow_run_count_n": "%d exécutions du workflow",
"actions.runs.all_workflows": "Toutes les procédures",
"actions.runs.other_workflows": "Autres procédures",
"actions.runs.other_workflows_tooltip": "Les procédures qui ont été exécutées dans ce dépôt mais qui nexistent pas dans la branche par défaut.",
"actions.runs.workflow_run_count_1": "%d exécution de procédure",
"actions.runs.workflow_run_count_n": "%d exécutions de procédure",
"actions.runs.commit": "Révision",
"actions.runs.run_details": "Détails de lexécution",
"actions.runs.workflow_file": "Fichier de flux de travail",
"actions.runs.workflow_file": "Déclaration de la procédure",
"actions.runs.workflow_file_no_permission": "Pas de permission pour voir la procédure",
"actions.runs.scheduled": "Planifié",
"actions.runs.pushed_by": "soumis par",
"actions.runs.invalid_workflow_helper": "La configuration du flux de travail est invalide. Veuillez vérifier votre fichier %s.",
"actions.runs.invalid_workflow_helper": "La déclaration de la procédure est invalide. Veuillez vérifier le fichier « %s ».",
"actions.runs.no_matching_online_runner_helper": "Aucun exécuteur en ligne correspondant au libellé %s",
"actions.runs.no_job_without_needs": "Le flux de travail doit contenir au moins une tâche sans dépendance.",
"actions.runs.no_job": "Le flux de travail doit contenir au moins une tâche",
"actions.runs.no_job_without_needs": "La procédure doit contenir au moins une mission sans dépendance.",
"actions.runs.no_job": "La procédure doit contenir au moins une mission.",
"actions.runs.invalid_reusable_workflow_uses": "Clause \"uses\" invalide dans la procédure : %s",
"actions.runs.actor": "Acteur",
"actions.runs.status": "Statut",
"actions.runs.actors_no_select": "Tous les acteurs",
@@ -3786,45 +3793,82 @@
"actions.runs.branch": "Branche",
"actions.runs.branches_no_select": "Toutes les branches",
"actions.runs.no_results": "Aucun résultat correspondant.",
"actions.runs.no_workflows": "Il n'y a pas encore de workflows.",
"actions.runs.no_workflows.quick_start": "Vous découvrez les Actions Gitea ? Consultez <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"%s\">le didacticiel</a>.",
"actions.runs.no_workflows.documentation": "Pour plus dinformations sur les actions Gitea, voir <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"%s\">la documentation</a>.",
"actions.runs.no_runs": "Le flux de travail n'a pas encore d'exécution.",
"actions.runs.no_workflows": "Il ny a pas de procédure ici.",
"actions.runs.no_workflows.quick_start": "Vous découvrez les Actions Gitea ? Consultez <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"%s\">le didacticiel</a>.",
"actions.runs.no_workflows.documentation": "Pour plus dinformations sur les Actions Gitea, voir <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"%s\">la documentation</a>.",
"actions.runs.no_runs": "Cette procédure na pas encore été exécutée.",
"actions.runs.empty_commit_message": "(message de révision vide)",
"actions.runs.expire_log_message": "Les journaux ont été supprimés car ils étaient trop anciens.",
"actions.runs.delete": "Supprimer cette exécution",
"actions.runs.cancel": "Annuler lexécution du flux",
"actions.runs.delete": "Effacer lexecution de cette procédure",
"actions.runs.cancel": "Annuler lexécution de cette procédure",
"actions.runs.delete.description": "Êtes-vous sûr de vouloir supprimer définitivement cette exécution ? Cette action ne peut pas être annulée.",
"actions.runs.not_done": "Cette exécution du flux de travail nest pas terminée.",
"actions.runs.view_workflow_file": "Voir le fichier du flux de travail",
"actions.runs.not_done": "Cette procédure nest pas terminée.",
"actions.runs.view_workflow_file": "Voir la déclaration de la procédure",
"actions.runs.summary": "Résumé",
"actions.runs.all_jobs": "Toutes les tâches",
"actions.runs.all_jobs": "Toutes les missions",
"actions.runs.job_summaries": "Résumé des missions",
"actions.runs.expand_caller_jobs": "Afficher les missions de cette procédure réutilisable",
"actions.runs.collapse_caller_jobs": "Masquer les missions de cette procédure réutilisable",
"actions.runs.attempt": "Tentative",
"actions.runs.latest": "Dernière",
"actions.runs.latest_attempt": "Dernière tentative",
"actions.runs.triggered_via": "Déclenché via %s",
"actions.runs.rerun_triggered": "Relance enclenchée",
"actions.runs.back_to_pull_request": "Retour à la demande dajout",
"actions.runs.back_to_workflow": "Retour à la procédure",
"actions.runs.total_duration": "Durée totale :",
"actions.runs.workflow_dependencies": "Dépendances de la procédure",
"actions.runs.graph_jobs_count_1": "%d mission",
"actions.runs.graph_jobs_count_n": "%d missions",
"actions.runs.graph_dependencies_count_1": "%d dépendance",
"actions.runs.graph_dependencies_count_n": "%d dépendances",
"actions.runs.graph_success_rate": "%s succès",
"actions.runs.graph_zoom_in": "Zoomer (Ctrl/⌘ + défilement)",
"actions.runs.graph_zoom_max": "Déjà zoomé à 100%",
"actions.runs.graph_zoom_out": "Dézoomer (Ctrl/⌘ + défilement)",
"actions.workflow.disable": "Désactiver le flux de travail",
"actions.workflow.disable_success": "Le flux de travail « %s » a bien été désactivé.",
"actions.workflow.enable": "Activer le flux de travail",
"actions.workflow.enable_success": "Le flux de travail « %s » a bien été activé.",
"actions.workflow.disabled": "Le flux de travail est désactivé.",
"actions.runs.graph_reset_view": "Rétablir",
"actions.workflow.disable": "Désactiver la procédure",
"actions.workflow.disable_success": "La procédure « %s » a bien été désactivée.",
"actions.workflow.enable": "Activer la procédure",
"actions.workflow.enable_success": "La procédure « %s » a bien été activée.",
"actions.workflow.disabled": "La procédure est désactivée.",
"actions.workflow.scope_owner": "Propriétaire",
"actions.workflow.scope_global": "Global",
"actions.workflow.required": "Requis",
"actions.workflow.run": "Exécuter le flux de travail",
"actions.workflow.not_found": "Flux de travail « %s » introuvable.",
"actions.workflow.run_success": "Le flux de travail « %s » sest correctement exécuté.",
"actions.workflow.from_ref": "Utiliser le flux de travail depuis",
"actions.workflow.has_workflow_dispatch": "Ce flux de travail a un déclencheur d’événement workflow_dispatch.",
"actions.workflow.has_no_workflow_dispatch": "Le flux de travail %s na pas de déclencheur d’événement workflow_dispatch.",
"actions.need_approval_desc": "Besoin dapprobation pour exécuter des flux de travail pour une demande dajout de bifurcation.",
"actions.approve_all_success": "Tous les flux de travail ont été acceptés.",
"actions.workflow.scoped_required_cannot_disable": "Cette procédure transversale est requise.",
"actions.scoped_workflows": "Procédures transversales",
"actions.scoped_workflows.desc_org": "Enrôlez un dépôt afin de rendre ses procédures accessibles à votre organisation. Toutes les procédures de la branche principale de ce dépôt seront ainsi exécutées dans chaque dépôt de cette organisation, comme si elles y avaient été créées.",
"actions.scoped_workflows.desc_user": "Enrôlez un dépôt afin de rendre ses procédures accessibles à votre compte. Toutes les procédures de la branche principale de ce dépôt seront ainsi exécutées dans chaque dépôt que vous possédez, comme si elles y avaient été créées.",
"actions.scoped_workflows.desc_global": "Enrôlez un dépôt afin de rendre ses procédures accessibles à lensemble du serveur. Toutes les procédures de la branche principale de ce dépôt seront ainsi exécutées dans chaque dépôt, comme si elles y avaient été créées. Sur un serveur volumineux, ces procédures peuvent lourdement solliciter les ressources du système.",
"actions.scoped_workflows.add_help": "Pour rendre des procédures transversales, soumettez leurs déclarations dans le dossier <code>%s</code> sur la branche par défaut de ce dépôt, puis enrôlez celui-ci ci-dessous.",
"actions.scoped_workflows.security_note": "Parce quune procédure transversale opère sur dautres dépôts que le sien, ses extrants sont journalisés sur ces dépôts et sont donc consultable par leurs utilisateurs. Ainsi, une procédure issue dun dépôt privé peut-être reconstruit à partir des journaux qu'elle produit. Exposer une procédure transversale peut donc compromètre la confidentialité de son dépôt hôte. Si une procédure transversale référence une autre procédure issue dun dépôt privé, assurez-vous que les dépôts affectés puissent également s'y référer, sans quoi ces procédures échoueront.",
"actions.scoped_workflows.source.add": "Enrôler un dépôt",
"actions.scoped_workflows.source.add_success": "Dépôt enrôlé.",
"actions.scoped_workflows.source.remove_success": "Dépôt retiré.",
"actions.scoped_workflows.source.not_found": "Dépôt introuvable.",
"actions.scoped_workflows.required.update_success": "Procédure requise mise à jour.",
"actions.scoped_workflows.required.label": "Marquer les procédures comme requises (elles ne pourront être désactivés depuis un dépôt) :",
"actions.scoped_workflows.required.patterns": "Motifs de signal requis",
"actions.scoped_workflows.required.patterns_aria": "Motifs de signal requis pour %s",
"actions.scoped_workflows.required.patterns_note": "est uniquement appliqué lorsque la procédure est requise",
"actions.scoped_workflows.required.patterns_hint": "Marquez la procédure comme requise pour configurer ses motifs de signal.",
"actions.scoped_workflows.required.patterns_help": "Un motif de signal par ligne. Une demande dajout concernée peut être fusionnée à condition quau moins un signal par motif ait réussi. Cela est imposé pour toutes les branches affectées ayant des règles de protections (même désactivées), mais pas les branches sans protections.",
"actions.scoped_workflows.required.patterns_empty": "Chaque procédure requise nécessite au moins un motif de signal.",
"actions.scoped_workflows.required.missing_file": "Le fichier nest plus dans le dépôt enrôlé.",
"actions.scoped_workflows.required.expected_contexts": "Signaux attendus (un signal qui correspond au motif est marqué)",
"actions.scoped_workflows.required.no_status_contexts": "Comme cette procédure ne publie aucun signal, la rentre obligatoire empêchera toutes demandes dajouts concernées d’être fusionnées. Préférez laisser cette procédure facultative.",
"actions.scoped_workflows.no_files": "Aucune procédure transversale n'a été trouvé dans la branche par défaut.",
"actions.workflow.run": "Réaliser la procédure",
"actions.workflow.create_status_badge": "Créer un badge d’état",
"actions.workflow.status_badge": "Badge d’état",
"actions.workflow.status_badge_url": "URL du badge",
"actions.workflow.not_found": "La procédure « %s » est introuvable.",
"actions.workflow.run_success": "La procédure « %s » est accomplie.",
"actions.workflow.from_ref": "Utiliser la procédure depuis",
"actions.workflow.has_workflow_dispatch": "Cette procédure dispose dun déclencheur workflow_dispatch.",
"actions.workflow.has_no_workflow_dispatch": "La procédure « %s » na pas de déclencheur workflow_dispatch.",
"actions.need_approval_desc": "Une approbation est nécessaire pour exécuter les procédures dune demande dajout de bifurcation.",
"actions.approve_all_success": "Toutes les procédures ont été approuvées.",
"actions.variables": "Variables",
"actions.variables.management": "Gestion des variables",
"actions.variables.creation": "Ajouter une variable",
@@ -3845,7 +3889,7 @@
"actions.general": "Général",
"actions.general.enable_actions": "Activer les actions",
"actions.general.collaborative_owners_management": "Gestion des collaborateurs",
"actions.general.collaborative_owners_management_help": "Un collaborateur est un utilisateur ou une organisation dont le dépôt privé peut accéder aux actions et flux de travail de ce dépôt.",
"actions.general.collaborative_owners_management_help": "Un collaborateur est un utilisateur ou une organisation dont le dépôt privé peut accéder aux actions et procédures de ce dépôt.",
"actions.general.add_collaborative_owner": "Ajouter un collaborateur",
"actions.general.collaborative_owner_not_exist": "Le collaborateur nexiste pas.",
"actions.general.remove_collaborative_owner": "Supprimer le collaborateur",
@@ -3865,19 +3909,19 @@
"org.repos.none": "Aucun dépôt.",
"actions.general.permissions": "Permissions du jeton des actions",
"actions.general.token_permissions.mode": "Permissions par défaut du jeton",
"actions.general.token_permissions.mode.desc": "Une tâche dActions utilisera les permissions par défaut si aucune nest déclarée dans le fichier du flux de travail.",
"actions.general.token_permissions.mode.desc": "Une mission dActions utilisera les permissions par défaut si aucune nest déclarée dans la procédure.",
"actions.general.token_permissions.mode.permissive": "Permissif",
"actions.general.token_permissions.mode.permissive.desc": "Permissions en lecture et écriture sur le dépôt de la tâche.",
"actions.general.token_permissions.mode.permissive.desc": "Permissions de consulter et modifier le dépôt dune mission.",
"actions.general.token_permissions.mode.restricted": "Restreint",
"actions.general.token_permissions.mode.restricted.desc": "Permissions en lecture seule pour le contenu (code, publications) sur le dépôt de la tâche.",
"actions.general.token_permissions.mode.restricted.desc": "Permissions de consulter uniquement le contenu (code, publications) du dépôt dune mission.",
"actions.general.token_permissions.override_owner": "Écraser la configuration faite par le propriétaire",
"actions.general.token_permissions.override_owner_desc": "Si actif, ce dépôt utilisera sa propre configuration pour les actions au lieu de respecter celle du propriétaire (utilisateur ou organisation).",
"actions.general.token_permissions.maximum": "Permissions maximales du jeton",
"actions.general.token_permissions.maximum.description": "Les permissions effectives de la tâche des actions seront limitées par les permissions maximales.",
"actions.general.token_permissions.fork_pr_note": "Si une tâche est démarrée par une demande de fusion depuis une bifurcation, ses permissions effectives ne dépasseront pas les permissions en lecture-seule.",
"actions.general.token_permissions.maximum.description": "Les permissions effectives de la mission des actions seront limitées par les permissions maximales.",
"actions.general.token_permissions.fork_pr_note": "Si une mission est démarrée par une demande dajout depuis une bifurcation, ses permissions effectives ne dépasseront pas les permissions en lecture-seule.",
"actions.general.token_permissions.customize_max_permissions": "Personnaliser les permissions maximales",
"actions.general.cross_repo": "Accès inter-dépôt",
"actions.general.cross_repo_desc": "Permet aux dépôts sélectionnés d’être visible en lecture-seule par tous les dépôts de ce propriétaire à laide de GITEA_TOKEN lors de lexécution des tâches dactions.",
"actions.general.cross_repo_desc": "Permet aux dépôts de ce propriétaire de consulter les dépôts sélectionnés, à laide du jeton GITEA_TOKEN lors de lexécution de missions dActions.",
"actions.general.cross_repo_selected": "Dépôts sélectionnés",
"actions.general.cross_repo_target_repos": "Dépôts cibles",
"actions.general.cross_repo_add": "Ajouter un dépôt cible"
+27
View File
@@ -3779,6 +3779,7 @@
"actions.runs.commit": "Tiomantas",
"actions.runs.run_details": "Sonraí Rith",
"actions.runs.workflow_file": "Comhad sreabhadh oibre",
"actions.runs.workflow_file_no_permission": "Gan cead chun an comhad sreafa oibre a fheiceáil",
"actions.runs.scheduled": "Sceidealaithe",
"actions.runs.pushed_by": "bhrú ag",
"actions.runs.invalid_workflow_helper": "Tá comhad cumraíochta sreabhadh oibre nebhailí. Seiceáil do chomhad cumraithe le do thoil: %s",
@@ -3835,7 +3836,33 @@
"actions.workflow.scope_owner": "Úinéir",
"actions.workflow.scope_global": "Domhanda",
"actions.workflow.required": "Riachtanach",
"actions.workflow.scoped_required_cannot_disable": "Tá an sreabhadh oibre raonaithe seo riachtanach agus ní féidir é a dhíchumasú.",
"actions.scoped_workflows": "Sreafaí Oibre Raonaithe",
"actions.scoped_workflows.desc_org": "Cláraigh stórtha mar fhoinsí sreabhadh oibre raonta. Ritheann comhaid sreabhadh oibre faoi eolairí sreabhadh oibre raonta brainse réamhshocraithe stórtha foinse ar gach stórtha den eagraíocht seo, i gcomhthéacs an stórtha sin féin.",
"actions.scoped_workflows.desc_user": "Cláraigh stórtha mar fhoinsí sreabhadh oibre raonta. Ritheann comhaid sreabhadh oibre faoi eolairí sreabhadh oibre raonta brainse réamhshocraithe stórtha foinse ar gach stór atá i do sheilbh, i gcomhthéacs an stórtha sin féin.",
"actions.scoped_workflows.desc_global": "Cláraigh stórtha mar fhoinsí sreabhadh oibre raonta. Ritheann comhaid sreabhadh oibre faoi eolairí sreabhadh oibre raonta brainse réamhshocraithe stórtha foinse ar gach stór ar an gcás seo, i gcomhthéacs an stórtha sin féin. Ós rud é go ndéantar foinsí ar leibhéal an chás a mheas ar imeachtaí gach stórtha, is féidir le clárú na gcomhad sin forchostais a chur leis ar chásanna móra.",
"actions.scoped_workflows.add_help": "Chun sreafaí oibre raonta a sholáthar ó stór, cuir na comhaid sreafa oibre faoi <code>%s</code> ar a bhrainse réamhshocraithe, agus ansin cláraigh an stór mar fhoinse thíos.",
"actions.scoped_workflows.security_note": "Déantar ábhar sreafa oibre stórais foinse a fhorghníomhú i ngach stórais lena mbaineann sé, agus scríobhtar a scripteanna céime agus a n-aschur chuig logaí Gníomhartha an stórais sin agus is féidir le duine ar bith ar féidir leo Gníomhartha an stórais ídigh a fheiceáil iad a léamh. Dá bhrí sin, nochtar loighic a sreafa oibre trí na logaí sin nuair a chláraítear stórais phríobháidigh mar fhoinse. Ní chláraítear ach stórais a bhféadfadh a n-ábhar sreafa oibre a bheith roinnte le gach stórais ídigh. Má thagraíonn sreabhadh oibre raonaithe do shreabhadh oibre in-athúsáidte ó stórais phríobháidigh, déan cinnte gur féidir le gach stórais ídigh é a léamh, nó teipfidh ar an sreabhadh oibre ansin.",
"actions.scoped_workflows.source.add": "Cuir stór foinse leis",
"actions.scoped_workflows.source.add_success": "Stór foinse curtha leis.",
"actions.scoped_workflows.source.remove_success": "Baineadh an stór foinse.",
"actions.scoped_workflows.source.not_found": "Níor aimsíodh an stórlann.",
"actions.scoped_workflows.required.update_success": "Sreafaí oibre riachtanacha nuashonraithe.",
"actions.scoped_workflows.required.label": "Marcáil sreafaí oibre mar riachtanacha (ní féidir le stórtha sreabhadh oibre riachtanach a dhíchumasú):",
"actions.scoped_workflows.required.patterns": "Patrúin seiceála stádais riachtanacha",
"actions.scoped_workflows.required.patterns_aria": "Patrúin seiceála stádais riachtanacha do %s",
"actions.scoped_workflows.required.patterns_note": "i bhfeidhm ach amháin nuair a bhíonn an sreabhadh oibre ag teastáil",
"actions.scoped_workflows.required.patterns_hint": "Marcáil an sreabhadh oibre mar is gá chun a phatrúin seiceála stádais a chumrú.",
"actions.scoped_workflows.required.patterns_help": "Patrún seiceála stádais amháin (glob) in aghaidh an líne. Ní féidir iarratas tarraingthe íditheach a chumasc ach amháin nuair a bheidh stádas a mheaitseálann gach patrún rite. Cuirtear é seo i bhfeidhm ar aon bhrainse sprice a bhfuil riail chosanta aige, fiú ceann a bhfuil a sheiceálacha stádais féin díchumasaithe; ní dhéantar geataíocht ar bhrainse sprice gan aon riail chosanta.",
"actions.scoped_workflows.required.patterns_empty": "Teastaíonn patrún seiceála stádais amháin ar a laghad ó gach sreabhadh oibre riachtanach.",
"actions.scoped_workflows.required.missing_file": "níl an comhad sa bhunleagan a thuilleadh",
"actions.scoped_workflows.required.expected_contexts": "Seiceálacha stádais ionchais (marcáiltear seic a mheaitseálann patrún)",
"actions.scoped_workflows.required.no_status_contexts": "Ní phostálann an sreabhadh oibre seo aon seiceálacha stádais, mar sin má mharcálann tú é mar riachtanas, chuirfeadh sé bac ar gach iarratas tarraingthe atá á úsáid ó chumasc. Díthiceáil Riachtanach.",
"actions.scoped_workflows.no_files": "Ní bhfuarthas aon chomhaid sreabha oibre raonaithe ar an mbrainse réamhshocraithe.",
"actions.workflow.run": "Rith Sreabhadh Oibre",
"actions.workflow.create_status_badge": "Cruthaigh suaitheantas stádais",
"actions.workflow.status_badge": "Suaitheantas Stádais",
"actions.workflow.status_badge_url": "URL suaitheantais",
"actions.workflow.not_found": "Níor aimsíodh sreabhadh oibre '%s'.",
"actions.workflow.run_success": "Ritheann sreabhadh oibre '%s' go rathúil.",
"actions.workflow.from_ref": "Úsáid sreabhadh oibre ó",
+6 -1
View File
@@ -1584,7 +1584,7 @@
"repo.issues.label_archived_filter": "아카이빙된 레이블 표시",
"repo.issues.label_archive_tooltip": "아카아빙된 레이블은 레이블로 검색할 때 기본적으로 제안 목록에서 제외됩니다.",
"repo.issues.label_exclusive_desc": "레이블명을 <code>스코프/항목</code>으로 지정하여 다른 <code>스코프/</code> 레이블과 상호 배타적으로 만드세요.",
"repo.issues.label_exclusive_warning": "이슈 또는 풀 리퀘스트의 레이블을 편집할 때 충돌하는 스코프 지정 레이블은 모두 제거됩니다.",
"repo.issues.label_exclusive_warning": "이슈 또는 풀 리퀘스트의 레이블을 편집할 때 충돌하는 범위지정 레이블은 모두 제거됩니다.",
"repo.issues.label_exclusive_order": "정렬 순서",
"repo.issues.label_exclusive_order_tooltip": "같은 스코프 내의 독점 레이블은 이 숫자 순서에 따라 정렬됩니다.",
"repo.issues.label_count": "레이블 %d개",
@@ -3820,7 +3820,12 @@
"actions.workflow.scope_owner": "소유자",
"actions.workflow.scope_global": "글로벌",
"actions.workflow.required": "필수 항목",
"actions.workflow.scoped_required_cannot_disable": "범위지정 워크플로우가 요구되며 비활성화할 수 없습니다.",
"actions.scoped_workflows": "범위지정 워크플로우",
"actions.workflow.run": "워크플로 실행",
"actions.workflow.create_status_badge": "상태 배지 생성",
"actions.workflow.status_badge": "상태 배지",
"actions.workflow.status_badge_url": "배지 URL",
"actions.workflow.not_found": "워크플로 '%s'를 찾을 수 없습니다.",
"actions.workflow.run_success": "워크플로 '%s'가 성공적으로 실행되었습니다.",
"actions.workflow.from_ref": "다음에서 워크플로 사용",
+24
View File
@@ -3776,6 +3776,7 @@
"actions.runs.commit": "Cometimento",
"actions.runs.run_details": "Detalhes da execução",
"actions.runs.workflow_file": "Ficheiro de sequência de trabalho",
"actions.runs.workflow_file_no_permission": "Sem permissão para ver o ficheiro da sequência de trabalho",
"actions.runs.scheduled": "Agendadas",
"actions.runs.pushed_by": "enviado por",
"actions.runs.invalid_workflow_helper": "O ficheiro de configuração da sequência de trabalho é inválido. Verifique o seu ficheiro de configuração: %s",
@@ -3832,6 +3833,29 @@
"actions.workflow.scope_owner": "Proprietário(a)",
"actions.workflow.scope_global": "Global",
"actions.workflow.required": "Obrigatório",
"actions.workflow.scoped_required_cannot_disable": "Esta sequência de trabalho de âmbito específico é obrigatória e não pode ser desabilitada.",
"actions.scoped_workflows": "Sequências de trabalho de âmbito específico",
"actions.scoped_workflows.desc_org": "Registe repositórios como fontes de sequências de trabalho de âmbito específico. Os ficheiros das sequências de trabalho dentro de pastas das sequências de trabalho de âmbito específico do ramo principal de um repositório fonte são executados em todos os repositórios desta organização, no próprio contexto desse repositório.",
"actions.scoped_workflows.desc_user": "Registe repositórios como fontes de sequências de trabalho de âmbito específico. Os ficheiros das sequências de trabalho dentro de pastas das sequências de trabalho de âmbito específico do ramo principal de um repositório fonte são executados em todos os seus repositórios, no próprio contexto desse repositório.",
"actions.scoped_workflows.desc_global": "Registe repositórios como fontes de sequências de trabalho de âmbito específico. Os ficheiros das sequências de trabalho dentro de pastas das sequências de trabalho de âmbito específico do ramo principal de um repositório fonte são executados em todos os repositórios desta instância, no próprio contexto desse repositório. Uma vez que as fontes ao nível da instância são avaliadas em todos os eventos do repositório, registá-las poderá acrescentar uma sobrecarga em instâncias grandes.",
"actions.scoped_workflows.add_help": "Para fornecer sequências de trabalho de âmbito específico a partir de um repositório, cometa os ficheiros da sequência de trabalho sob <code>%s</code> no seu ramo principal e depois registe o repositório como uma fonte abaixo.",
"actions.scoped_workflows.security_note": "O conteúdo da sequência de trabalho de um repositório de origem é executado em todos os repositórios aos quais se aplica e os seus scripts de etapas, bem como os seus resultados, são escritos nos registos das operações desse repositório e podem ser lidos por qualquer pessoa que tenha permissão para ver as operações do repositório consumidor. Portanto, registar um repositório privado como uma fonte divulga a lógica da sequência de trabalho através desses registos. Registe apenas repositórios cujo conteúdo da sequência de trabalho possa ser partilhado com todos os repositórios consumidores. Se uma sequência de trabalho de âmbito específico fizer referência a uma sequência de trabalho reutilizável de um repositório privado, certifique-se que todos os repositórios consumidores a podem ler, caso contrário a sequência de trabalho irá falhar aí.",
"actions.scoped_workflows.source.add": "Adicionar repositório de origem",
"actions.scoped_workflows.source.add_success": "Repositório de origem adicionado.",
"actions.scoped_workflows.source.remove_success": "Repositório de origem removido.",
"actions.scoped_workflows.source.not_found": "Repositório não encontrado.",
"actions.scoped_workflows.required.update_success": "As sequências de trabalho obrigatórias foram refrescadas.",
"actions.scoped_workflows.required.label": "Marcar sequências de trabalho como sendo obrigatórias (uma sequência de trabalho obrigatória não pode ser desabilitada pelos repositórios):",
"actions.scoped_workflows.required.patterns": "Padrões de verificação de estado obrigatórios",
"actions.scoped_workflows.required.patterns_aria": "Padrões de verificação de estado obrigatórios para %s",
"actions.scoped_workflows.required.patterns_note": "aplicada apenas enquanto a sequência de trabalho for obrigatória",
"actions.scoped_workflows.required.patterns_hint": "Marque a sequência de trabalho como sendo obrigatória para configurar os seus padrões de verificação de estado.",
"actions.scoped_workflows.required.patterns_help": "Um padrão de verificação de estado (glob) por linha. Um pedido de integração consumidor só pode ser executado depois de ter sido aprovado um estado que corresponda a todos os padrões. Esta regra é aplicada a qualquer ramo de destino que tenha uma regra de salvaguarda, mesmo que as suas próprias verificações de estado estejam desabilitadas; um ramo de destino sem regra de salvaguarda não está sujeito a restrições.",
"actions.scoped_workflows.required.patterns_empty": "Cada sequência de trabalho obrigatória precisa de pelo menos um padrão de verificação de estado.",
"actions.scoped_workflows.required.missing_file": "o ficheiro já não está na origem",
"actions.scoped_workflows.required.expected_contexts": "Verificações de estado esperadas (está marcada uma verificação que corresponde a um padrão)",
"actions.scoped_workflows.required.no_status_contexts": "Esta sequência de trabalho não faz verificações de estado; por isso, marcá-la como obrigatória impediria a execução de todos os pedidos de integração que a utilizam. Desmarque a opção «Obrigatória».",
"actions.scoped_workflows.no_files": "Não foram encontrados quaisquer ficheiros de sequência de trabalho de âmbito específico no ramo principal.",
"actions.workflow.run": "Executar sequência de trabalho",
"actions.workflow.create_status_badge": "Criar distintivo de estado",
"actions.workflow.status_badge": "Distintivo de estado",
+6 -10
View File
@@ -50,7 +50,7 @@
"esbuild": "0.28.1",
"idiomorph": "0.7.4",
"jquery": "4.0.0",
"js-yaml": "4.2.0",
"js-yaml": "5.1.0",
"katex": "0.17.0",
"mermaid": "11.15.0",
"online-3d-viewer": "0.18.0",
@@ -70,7 +70,6 @@
"vite": "8.1.0",
"vite-string-plugin": "2.0.4",
"vue": "3.5.38",
"vue-bar-graph": "2.2.0",
"vue-chartjs": "5.3.3"
},
"devDependencies": {
@@ -81,9 +80,8 @@
"@stylistic/stylelint-plugin": "5.2.0",
"@types/codemirror": "5.60.17",
"@types/jquery": "4.0.1",
"@types/js-yaml": "4.0.9",
"@types/katex": "0.16.8",
"@types/node": "25.9.4",
"@types/node": "26.0.1",
"@types/pdfobject": "2.2.5",
"@types/sortablejs": "1.15.9",
"@types/swagger-ui-dist": "3.30.6",
@@ -92,15 +90,13 @@
"@typescript-eslint/parser": "8.62.0",
"@vitejs/plugin-vue": "6.0.7",
"@vitest/eslint-plugin": "1.6.20",
"eslint": "10.5.0",
"eslint": "10.6.0",
"eslint-import-resolver-typescript": "4.4.5",
"eslint-plugin-array-func": "5.1.1",
"eslint-plugin-de-morgan": "2.1.2",
"eslint-plugin-import-x": "4.17.0",
"eslint-plugin-import-x": "4.17.1",
"eslint-plugin-playwright": "2.10.4",
"eslint-plugin-regexp": "3.1.0",
"eslint-plugin-regexp": "3.1.1",
"eslint-plugin-sonarjs": "4.1.0",
"eslint-plugin-unicorn": "68.0.0",
"eslint-plugin-unicorn": "69.0.0",
"eslint-plugin-vue": "10.9.2",
"eslint-plugin-vue-scoped-css": "3.1.1",
"eslint-plugin-wc": "3.1.0",
+143 -181
View File
@@ -94,7 +94,7 @@ importers:
version: 2.6.2
'@vitejs/plugin-vue':
specifier: 6.0.7
version: 6.0.7(vite@8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.38(typescript@6.0.3))
version: 6.0.7(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.38(typescript@6.0.3))
ansi_up:
specifier: 6.0.6
version: 6.0.6
@@ -141,8 +141,8 @@ importers:
specifier: 4.0.0
version: 4.0.0
js-yaml:
specifier: 4.2.0
version: 4.2.0
specifier: 5.1.0
version: 5.1.0
katex:
specifier: 0.17.0
version: 0.17.0
@@ -193,23 +193,20 @@ importers:
version: 0.7.2
vite:
specifier: 8.1.0
version: 8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)
version: 8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)
vite-string-plugin:
specifier: 2.0.4
version: 2.0.4(vite@8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))
version: 2.0.4(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))
vue:
specifier: 3.5.38
version: 3.5.38(typescript@6.0.3)
vue-bar-graph:
specifier: 2.2.0
version: 2.2.0(typescript@6.0.3)
vue-chartjs:
specifier: 5.3.3
version: 5.3.3(chart.js@4.5.1)(vue@3.5.38(typescript@6.0.3))
devDependencies:
'@eslint-community/eslint-plugin-eslint-comments':
specifier: 4.7.2
version: 4.7.2(eslint@10.5.0(jiti@2.7.0))
version: 4.7.2(eslint@10.6.0(jiti@2.7.0))
'@eslint/json':
specifier: 2.0.0
version: 2.0.0
@@ -218,7 +215,7 @@ importers:
version: 1.61.1
'@stylistic/eslint-plugin':
specifier: 5.10.0
version: 5.10.0(eslint@10.5.0(jiti@2.7.0))
version: 5.10.0(eslint@10.6.0(jiti@2.7.0))
'@stylistic/stylelint-plugin':
specifier: 5.2.0
version: 5.2.0(stylelint@17.13.0(typescript@6.0.3))
@@ -228,15 +225,12 @@ importers:
'@types/jquery':
specifier: 4.0.1
version: 4.0.1
'@types/js-yaml':
specifier: 4.0.9
version: 4.0.9
'@types/katex':
specifier: 0.16.8
version: 0.16.8
'@types/node':
specifier: 25.9.4
version: 25.9.4
specifier: 26.0.1
version: 26.0.1
'@types/pdfobject':
specifier: 2.2.5
version: 2.2.5
@@ -254,46 +248,40 @@ importers:
version: 1.12.4
'@typescript-eslint/parser':
specifier: 8.62.0
version: 8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
version: 8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
'@vitest/eslint-plugin':
specifier: 1.6.20
version: 1.6.20(@typescript-eslint/eslint-plugin@8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)(vitest@4.1.9(@types/node@25.9.4)(happy-dom@20.10.6)(jsdom@20.0.3)(vite@8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)))
version: 1.6.20(@typescript-eslint/eslint-plugin@8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)(vitest@4.1.9(@types/node@26.0.1)(happy-dom@20.10.6)(jsdom@20.0.3)(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)))
eslint:
specifier: 10.5.0
version: 10.5.0(jiti@2.7.0)
specifier: 10.6.0
version: 10.6.0(jiti@2.7.0)
eslint-import-resolver-typescript:
specifier: 4.4.5
version: 4.4.5(eslint-plugin-import-x@4.17.0(@typescript-eslint/utils@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.5.0(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@10.5.0(jiti@2.7.0))
eslint-plugin-array-func:
specifier: 5.1.1
version: 5.1.1(eslint@10.5.0(jiti@2.7.0))
eslint-plugin-de-morgan:
specifier: 2.1.2
version: 2.1.2(eslint@10.5.0(jiti@2.7.0))
version: 4.4.5(eslint-plugin-import-x@4.17.1(@typescript-eslint/utils@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.6.0(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@10.6.0(jiti@2.7.0))
eslint-plugin-import-x:
specifier: 4.17.0
version: 4.17.0(@typescript-eslint/utils@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.5.0(jiti@2.7.0))
specifier: 4.17.1
version: 4.17.1(@typescript-eslint/utils@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.6.0(jiti@2.7.0))
eslint-plugin-playwright:
specifier: 2.10.4
version: 2.10.4(eslint@10.5.0(jiti@2.7.0))
version: 2.10.4(eslint@10.6.0(jiti@2.7.0))
eslint-plugin-regexp:
specifier: 3.1.0
version: 3.1.0(eslint@10.5.0(jiti@2.7.0))
specifier: 3.1.1
version: 3.1.1(eslint@10.6.0(jiti@2.7.0))
eslint-plugin-sonarjs:
specifier: 4.1.0
version: 4.1.0(eslint@10.5.0(jiti@2.7.0))
version: 4.1.0(eslint@10.6.0(jiti@2.7.0))
eslint-plugin-unicorn:
specifier: 68.0.0
version: 68.0.0(eslint@10.5.0(jiti@2.7.0))
specifier: 69.0.0
version: 69.0.0(eslint@10.6.0(jiti@2.7.0))
eslint-plugin-vue:
specifier: 10.9.2
version: 10.9.2(@stylistic/eslint-plugin@5.10.0(eslint@10.5.0(jiti@2.7.0)))(@typescript-eslint/parser@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.5.0(jiti@2.7.0))(vue-eslint-parser@10.4.0(eslint@10.5.0(jiti@2.7.0)))
version: 10.9.2(@stylistic/eslint-plugin@5.10.0(eslint@10.6.0(jiti@2.7.0)))(@typescript-eslint/parser@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(vue-eslint-parser@10.4.0(eslint@10.6.0(jiti@2.7.0)))
eslint-plugin-vue-scoped-css:
specifier: 3.1.1
version: 3.1.1(eslint@10.5.0(jiti@2.7.0))(vue-eslint-parser@10.4.0(eslint@10.5.0(jiti@2.7.0)))
version: 3.1.1(eslint@10.6.0(jiti@2.7.0))(vue-eslint-parser@10.4.0(eslint@10.6.0(jiti@2.7.0)))
eslint-plugin-wc:
specifier: 3.1.0
version: 3.1.0(eslint@10.5.0(jiti@2.7.0))
version: 3.1.0(eslint@10.6.0(jiti@2.7.0))
globals:
specifier: 17.7.0
version: 17.7.0
@@ -338,13 +326,13 @@ importers:
version: 6.0.3
typescript-eslint:
specifier: 8.62.0
version: 8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
version: 8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
updates:
specifier: 17.18.0
version: 17.18.0
vitest:
specifier: 4.1.9
version: 4.1.9(@types/node@25.9.4)(happy-dom@20.10.6)(jsdom@20.0.3)(vite@8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))
version: 4.1.9(@types/node@26.0.1)(happy-dom@20.10.6)(jsdom@20.0.3)(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))
vue-tsc:
specifier: 3.3.5
version: 3.3.5(typescript@6.0.3)
@@ -1313,9 +1301,6 @@ packages:
'@types/jquery@4.0.1':
resolution: {integrity: sha512-9a59A/tycXgYuPABcp6/3spSShn0NT2UOM4EfHvMumjYi4lJWTsK5SZWjhx3yRm9IHGCeWXdV2YfNsrWrft/CA==}
'@types/js-yaml@4.0.9':
resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==}
'@types/jsdom@20.0.1':
resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==}
@@ -1334,8 +1319,8 @@ packages:
'@types/ms@2.1.0':
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
'@types/node@25.9.4':
resolution: {integrity: sha512-dszCsrKb5U7ZsVZBWiHFklTloVl0mSEnWH/iZXfZUlI4rzCUnsvGmgqfuVRHL54ugE7/wRuxEIXRa2iMZ+BG6g==}
'@types/node@26.0.1':
resolution: {integrity: sha512-fc3KiUoBt6kie0N9bIW3E47vZsuaMf0PM2AaUpLCLT0s/LvX1nxAim6Fc049cNxODPpGm6qRAuUOB86SkRuPQw==}
'@types/pdfobject@2.2.5':
resolution: {integrity: sha512-7gD5tqc/RUDq0PyoLemL0vEHxBYi+zY0WVaFAx/Y0jBsXFgot1vB9No1GhDZGwRGJMCIZbgAb74QG9MTyTNU/g==}
@@ -2440,20 +2425,8 @@ packages:
eslint-import-resolver-webpack:
optional: true
eslint-plugin-array-func@5.1.1:
resolution: {integrity: sha512-TbVGk+yLqXHgtrS4DnYzg2Ycuk5y+lYFy5NgT748neQdJvNIYUucxp2QQjPU7dwbs9xp9fyktgtK069y9rNdig==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: '>=8.51.0'
eslint-plugin-de-morgan@2.1.2:
resolution: {integrity: sha512-6/MXP77FUrFGTdJ2Lny3Jv027bE3SUHDf+/VBUBckpH5TskOY5G4UX+AebqJeUpt3nXjy3S0KWBRwTItVQwgvw==}
engines: {node: ^20.0.0 || >=22.0.0}
peerDependencies:
eslint: ^8.45.0 || ^9.0.0 || ^10.0.0
eslint-plugin-import-x@4.17.0:
resolution: {integrity: sha512-aM7V25Bg6YuYxtEhwjafzfS0NTMds1D2PMQI0K4KqJxQJRtkP4CO+MQTWRdBq2qAnmPxTxLevhXUBtByxJqS1w==}
eslint-plugin-import-x@4.17.1:
resolution: {integrity: sha512-4cdstYkKCyjumM2Q9NSI03K8D2a9F4Ssz33K2lv2hQa4KmR9jPLwk3uWGtNvclfqBrPGfGuMBwsGMbe6dMRbfg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@typescript-eslint/utils': ^8.56.0
@@ -2481,8 +2454,8 @@ packages:
peerDependencies:
eslint: '>=8.40.0'
eslint-plugin-regexp@3.1.0:
resolution: {integrity: sha512-qGXIC3DIKZHcK1H9A9+Byz9gmndY6TTSRkSMTZpNXdyCw2ObSehRgccJv35n9AdUakEjQp5VFNLas6BMXizCZg==}
eslint-plugin-regexp@3.1.1:
resolution: {integrity: sha512-MxR5nqoQCtVWmJwia0D2+NlXX1xzdpkslsVOZLEYQ4PQWEaL65PCZXURxaBc3lPnkNFpNxzMIRmYVxdl8giXRA==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
peerDependencies:
eslint: '>=9.38.0'
@@ -2492,8 +2465,8 @@ packages:
peerDependencies:
eslint: ^8.0.0 || ^9.0.0 || ^10.0.0
eslint-plugin-unicorn@68.0.0:
resolution: {integrity: sha512-mHYWvX948Q4H3bGc39bsNMxD/leOuNI+Iws9NVsoSz5VA7EGP86wnz7mZ/SPSvRhefT8L4hd8DHfDuGC+lIoCQ==}
eslint-plugin-unicorn@69.0.0:
resolution: {integrity: sha512-ZN/KtHr9hQ6AOByANSNJpsDbo/+Nn+EyQ6blK4w+dcmS/xpYkqLLfrUc+NA/wOK6vF5uEUvhn8my5B/3sruB9g==}
engines: {node: '>=22'}
peerDependencies:
eslint: '>=10.4'
@@ -2547,8 +2520,8 @@ packages:
resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
eslint@10.5.0:
resolution: {integrity: sha512-1y+7C+vi12bUK1IpZeaV3gsH9fHLBmPvYmPx42pvT/E9yG0IC8g3PUZZgp0+JLJl7ZDK0flc2gc+Aw9dpCvIsQ==}
eslint@10.6.0:
resolution: {integrity: sha512-6lVbcqSodALYo+4ELD0heG6lFiFxnLMuLkiMi2qV8LMp54N8tE8FT1GMH+ev4Ti00nFjNze2+Su6DsV5OQW3Dg==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
hasBin: true
peerDependencies:
@@ -3068,6 +3041,10 @@ packages:
resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==}
hasBin: true
js-yaml@5.1.0:
resolution: {integrity: sha512-s8VA5jkR8f22S3NAXmhKPFqGUduqZGlsufabVOgN14iTdw/RXcym7bKkbwjxLK9Yw2lEvvmJjFp119+KPeo8Kg==}
hasBin: true
jsdoc-type-pratt-parser@7.2.0:
resolution: {integrity: sha512-dh140MMgjyg3JhJZY/+iEzW+NO5xR2gpbDFKHqotCmexElVntw7GjWjt511+C/Ef02RU5TKYrJo/Xlzk+OLaTw==}
engines: {node: '>=20.0.0'}
@@ -4184,8 +4161,8 @@ packages:
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
engines: {node: '>= 0.4'}
undici-types@7.24.6:
resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==}
undici-types@8.3.0:
resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==}
unicorn-magic@0.4.0:
resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==}
@@ -4317,9 +4294,6 @@ packages:
vscode-uri@3.1.0:
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
vue-bar-graph@2.2.0:
resolution: {integrity: sha512-1xFPho2nM6nFDziExLu48vKO+Q90gjxz1NyHfc+MhgfYDSxR9BMyhOIXUO5EmwKIVEX5dBoP2n3Ius8SjKRD4g==}
vue-chartjs@5.3.3:
resolution: {integrity: sha512-jqxtL8KZ6YJ5NTv6XzrzLS7osyegOi28UGNZW0h9OkDL7Sh1396ht4Dorh04aKrl2LiSalQ84WtqiG0RIJb0tA==}
peerDependencies:
@@ -4939,15 +4913,15 @@ snapshots:
'@esbuild/win32-x64@0.28.1':
optional: true
'@eslint-community/eslint-plugin-eslint-comments@4.7.2(eslint@10.5.0(jiti@2.7.0))':
'@eslint-community/eslint-plugin-eslint-comments@4.7.2(eslint@10.6.0(jiti@2.7.0))':
dependencies:
escape-string-regexp: 4.0.0
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
ignore: 7.0.5
'@eslint-community/eslint-utils@4.9.1(eslint@10.5.0(jiti@2.7.0))':
'@eslint-community/eslint-utils@4.9.1(eslint@10.6.0(jiti@2.7.0))':
dependencies:
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.2': {}
@@ -5023,14 +4997,14 @@ snapshots:
dependencies:
'@jest/fake-timers': 29.7.0
'@jest/types': 29.6.3
'@types/node': 25.9.4
'@types/node': 26.0.1
jest-mock: 29.7.0
'@jest/fake-timers@29.7.0':
dependencies:
'@jest/types': 29.6.3
'@sinonjs/fake-timers': 10.3.0
'@types/node': 25.9.4
'@types/node': 26.0.1
jest-message-util: 29.7.0
jest-mock: 29.7.0
jest-util: 29.7.0
@@ -5044,7 +5018,7 @@ snapshots:
'@jest/schemas': 29.6.3
'@types/istanbul-lib-coverage': 2.0.6
'@types/istanbul-reports': 3.0.4
'@types/node': 25.9.4
'@types/node': 26.0.1
'@types/yargs': 17.0.35
chalk: 4.1.2
@@ -5357,11 +5331,11 @@ snapshots:
'@standard-schema/spec@1.1.0': {}
'@stylistic/eslint-plugin@5.10.0(eslint@10.5.0(jiti@2.7.0))':
'@stylistic/eslint-plugin@5.10.0(eslint@10.6.0(jiti@2.7.0))':
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0(jiti@2.7.0))
'@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0))
'@typescript-eslint/types': 8.62.0
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
eslint-visitor-keys: 4.2.1
espree: 10.4.0
estraverse: 5.3.0
@@ -5541,11 +5515,9 @@ snapshots:
'@types/jquery@4.0.1': {}
'@types/js-yaml@4.0.9': {}
'@types/jsdom@20.0.1':
dependencies:
'@types/node': 25.9.4
'@types/node': 26.0.1
'@types/tough-cookie': 4.0.5
parse5: 7.3.0
@@ -5560,9 +5532,9 @@ snapshots:
'@types/ms@2.1.0': {}
'@types/node@25.9.4':
'@types/node@26.0.1':
dependencies:
undici-types: 7.24.6
undici-types: 8.3.0
'@types/pdfobject@2.2.5': {}
@@ -5591,7 +5563,7 @@ snapshots:
'@types/ws@8.18.1':
dependencies:
'@types/node': 25.9.4
'@types/node': 26.0.1
'@types/yargs-parser@21.0.3': {}
@@ -5599,15 +5571,15 @@ snapshots:
dependencies:
'@types/yargs-parser': 21.0.3
'@typescript-eslint/eslint-plugin@8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)':
'@typescript-eslint/eslint-plugin@8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/parser': 8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/scope-manager': 8.62.0
'@typescript-eslint/type-utils': 8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/utils': 8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/type-utils': 8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/utils': 8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/visitor-keys': 8.62.0
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
ignore: 7.0.5
natural-compare: 1.4.0
ts-api-utils: 2.5.0(typescript@6.0.3)
@@ -5615,14 +5587,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)':
'@typescript-eslint/parser@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.62.0
'@typescript-eslint/types': 8.62.0
'@typescript-eslint/typescript-estree': 8.62.0(typescript@6.0.3)
'@typescript-eslint/visitor-keys': 8.62.0
debug: 4.4.3
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
typescript: 6.0.3
transitivePeerDependencies:
- supports-color
@@ -5645,13 +5617,13 @@ snapshots:
dependencies:
typescript: 6.0.3
'@typescript-eslint/type-utils@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)':
'@typescript-eslint/type-utils@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)':
dependencies:
'@typescript-eslint/types': 8.62.0
'@typescript-eslint/typescript-estree': 8.62.0(typescript@6.0.3)
'@typescript-eslint/utils': 8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/utils': 8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
debug: 4.4.3
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
ts-api-utils: 2.5.0(typescript@6.0.3)
typescript: 6.0.3
transitivePeerDependencies:
@@ -5674,13 +5646,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)':
'@typescript-eslint/utils@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0(jiti@2.7.0))
'@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0))
'@typescript-eslint/scope-manager': 8.62.0
'@typescript-eslint/types': 8.62.0
'@typescript-eslint/typescript-estree': 8.62.0(typescript@6.0.3)
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
typescript: 6.0.3
transitivePeerDependencies:
- supports-color
@@ -5765,21 +5737,21 @@ snapshots:
d3-selection: 3.0.0
d3-transition: 3.0.1(d3-selection@3.0.0)
'@vitejs/plugin-vue@6.0.7(vite@8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.38(typescript@6.0.3))':
'@vitejs/plugin-vue@6.0.7(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.38(typescript@6.0.3))':
dependencies:
'@rolldown/pluginutils': 1.0.1
vite: 8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)
vite: 8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)
vue: 3.5.38(typescript@6.0.3)
'@vitest/eslint-plugin@1.6.20(@typescript-eslint/eslint-plugin@8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)(vitest@4.1.9(@types/node@25.9.4)(happy-dom@20.10.6)(jsdom@20.0.3)(vite@8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)))':
'@vitest/eslint-plugin@1.6.20(@typescript-eslint/eslint-plugin@8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)(vitest@4.1.9(@types/node@26.0.1)(happy-dom@20.10.6)(jsdom@20.0.3)(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)))':
dependencies:
'@typescript-eslint/scope-manager': 8.62.0
'@typescript-eslint/utils': 8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
eslint: 10.5.0(jiti@2.7.0)
'@typescript-eslint/utils': 8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
eslint: 10.6.0(jiti@2.7.0)
optionalDependencies:
'@typescript-eslint/eslint-plugin': 8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/eslint-plugin': 8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
typescript: 6.0.3
vitest: 4.1.9(@types/node@25.9.4)(happy-dom@20.10.6)(jsdom@20.0.3)(vite@8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))
vitest: 4.1.9(@types/node@26.0.1)(happy-dom@20.10.6)(jsdom@20.0.3)(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))
transitivePeerDependencies:
- supports-color
@@ -5792,13 +5764,13 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.1.0
'@vitest/mocker@4.1.9(vite@8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))':
'@vitest/mocker@4.1.9(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))':
dependencies:
'@vitest/spy': 4.1.9
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)
vite: 8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)
'@vitest/pretty-format@4.1.9':
dependencies:
@@ -6075,7 +6047,7 @@ snapshots:
buffer-image-size@0.6.4:
dependencies:
'@types/node': 25.9.4
'@types/node': 26.0.1
buffer@5.7.1:
dependencies:
@@ -6765,10 +6737,10 @@ snapshots:
- supports-color
optional: true
eslint-import-resolver-typescript@4.4.5(eslint-plugin-import-x@4.17.0(@typescript-eslint/utils@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.5.0(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@10.5.0(jiti@2.7.0)):
eslint-import-resolver-typescript@4.4.5(eslint-plugin-import-x@4.17.1(@typescript-eslint/utils@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.6.0(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@10.6.0(jiti@2.7.0)):
dependencies:
debug: 4.4.3
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
eslint-import-context: 0.1.9(unrs-resolver@1.12.2)
get-tsconfig: 4.14.0
is-bun-module: 2.0.0
@@ -6776,37 +6748,29 @@ snapshots:
tinyglobby: 0.2.17
unrs-resolver: 1.12.2
optionalDependencies:
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.5)(eslint@10.5.0(jiti@2.7.0))
eslint-plugin-import-x: 4.17.0(@typescript-eslint/utils@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.5.0(jiti@2.7.0))
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.5)(eslint@10.6.0(jiti@2.7.0))
eslint-plugin-import-x: 4.17.1(@typescript-eslint/utils@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.6.0(jiti@2.7.0))
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.13.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@4.4.5)(eslint@10.5.0(jiti@2.7.0)):
eslint-module-utils@2.13.0(@typescript-eslint/parser@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@4.4.5)(eslint@10.6.0(jiti@2.7.0)):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
eslint: 10.5.0(jiti@2.7.0)
'@typescript-eslint/parser': 8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
eslint: 10.6.0(jiti@2.7.0)
eslint-import-resolver-node: 0.3.10
eslint-import-resolver-typescript: 4.4.5(eslint-plugin-import-x@4.17.0(@typescript-eslint/utils@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.5.0(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@10.5.0(jiti@2.7.0))
eslint-import-resolver-typescript: 4.4.5(eslint-plugin-import-x@4.17.1(@typescript-eslint/utils@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.6.0(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@10.6.0(jiti@2.7.0))
transitivePeerDependencies:
- supports-color
optional: true
eslint-plugin-array-func@5.1.1(eslint@10.5.0(jiti@2.7.0)):
dependencies:
eslint: 10.5.0(jiti@2.7.0)
eslint-plugin-de-morgan@2.1.2(eslint@10.5.0(jiti@2.7.0)):
dependencies:
eslint: 10.5.0(jiti@2.7.0)
eslint-plugin-import-x@4.17.0(@typescript-eslint/utils@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.5.0(jiti@2.7.0)):
eslint-plugin-import-x@4.17.1(@typescript-eslint/utils@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.6.0(jiti@2.7.0)):
dependencies:
'@typescript-eslint/types': 8.62.0
comment-parser: 1.4.7
debug: 4.4.3
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
eslint-import-context: 0.1.9(unrs-resolver@1.12.2)
is-glob: 4.0.3
minimatch: 10.2.5
@@ -6814,12 +6778,12 @@ snapshots:
stable-hash-x: 0.2.0
unrs-resolver: 1.12.2
optionalDependencies:
'@typescript-eslint/utils': 8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/utils': 8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
eslint-import-resolver-node: 0.3.10
transitivePeerDependencies:
- supports-color
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.5)(eslint@10.5.0(jiti@2.7.0)):
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.5)(eslint@10.6.0(jiti@2.7.0)):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.9
@@ -6828,9 +6792,9 @@ snapshots:
array.prototype.flatmap: 1.3.3
debug: 3.2.7
doctrine: 2.1.0
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
eslint-import-resolver-node: 0.3.10
eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@4.4.5)(eslint@10.5.0(jiti@2.7.0))
eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@4.4.5)(eslint@10.6.0(jiti@2.7.0))
hasown: 2.0.4
is-core-module: 2.16.2
is-glob: 4.0.3
@@ -6842,35 +6806,35 @@ snapshots:
string.prototype.trimend: 1.0.9
tsconfig-paths: 3.15.0
optionalDependencies:
'@typescript-eslint/parser': 8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/parser': 8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
- supports-color
optional: true
eslint-plugin-playwright@2.10.4(eslint@10.5.0(jiti@2.7.0)):
eslint-plugin-playwright@2.10.4(eslint@10.6.0(jiti@2.7.0)):
dependencies:
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
globals: 17.7.0
eslint-plugin-regexp@3.1.0(eslint@10.5.0(jiti@2.7.0)):
eslint-plugin-regexp@3.1.1(eslint@10.6.0(jiti@2.7.0)):
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0(jiti@2.7.0))
'@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0))
'@eslint-community/regexpp': 4.12.2
comment-parser: 1.4.7
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
jsdoc-type-pratt-parser: 7.2.0
refa: 0.12.1
regexp-ast-analysis: 0.7.1
scslre: 0.3.0
eslint-plugin-sonarjs@4.1.0(eslint@10.5.0(jiti@2.7.0)):
eslint-plugin-sonarjs@4.1.0(eslint@10.6.0(jiti@2.7.0)):
dependencies:
'@eslint-community/regexpp': 4.12.2
builtin-modules: 3.3.0
bytes: 3.1.2
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
functional-red-black-tree: 1.0.1
globals: 17.7.0
jsx-ast-utils-x: 0.1.0
@@ -6882,16 +6846,16 @@ snapshots:
typescript: 6.0.3
yaml: 2.9.0
eslint-plugin-unicorn@68.0.0(eslint@10.5.0(jiti@2.7.0)):
eslint-plugin-unicorn@69.0.0(eslint@10.6.0(jiti@2.7.0)):
dependencies:
'@babel/helper-validator-identifier': 7.29.7
'@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0(jiti@2.7.0))
'@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0))
browserslist: 4.28.2
change-case: 5.4.4
ci-info: 4.4.0
core-js-compat: 3.49.0
detect-indent: 7.0.2
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
find-up-simple: 1.0.1
globals: 17.7.0
indent-string: 5.0.0
@@ -6902,33 +6866,33 @@ snapshots:
semver: 7.8.4
strip-indent: 4.1.1
eslint-plugin-vue-scoped-css@3.1.1(eslint@10.5.0(jiti@2.7.0))(vue-eslint-parser@10.4.0(eslint@10.5.0(jiti@2.7.0))):
eslint-plugin-vue-scoped-css@3.1.1(eslint@10.6.0(jiti@2.7.0))(vue-eslint-parser@10.4.0(eslint@10.6.0(jiti@2.7.0))):
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0(jiti@2.7.0))
'@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0))
es-toolkit: 1.47.0
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
postcss: 8.5.15
postcss-safe-parser: 7.0.1(postcss@8.5.15)
postcss-selector-parser: 7.1.1
vue-eslint-parser: 10.4.0(eslint@10.5.0(jiti@2.7.0))
vue-eslint-parser: 10.4.0(eslint@10.6.0(jiti@2.7.0))
eslint-plugin-vue@10.9.2(@stylistic/eslint-plugin@5.10.0(eslint@10.5.0(jiti@2.7.0)))(@typescript-eslint/parser@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.5.0(jiti@2.7.0))(vue-eslint-parser@10.4.0(eslint@10.5.0(jiti@2.7.0))):
eslint-plugin-vue@10.9.2(@stylistic/eslint-plugin@5.10.0(eslint@10.6.0(jiti@2.7.0)))(@typescript-eslint/parser@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(vue-eslint-parser@10.4.0(eslint@10.6.0(jiti@2.7.0))):
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0(jiti@2.7.0))
eslint: 10.5.0(jiti@2.7.0)
'@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0))
eslint: 10.6.0(jiti@2.7.0)
natural-compare: 1.4.0
nth-check: 2.1.1
postcss-selector-parser: 7.1.1
semver: 7.8.4
vue-eslint-parser: 10.4.0(eslint@10.5.0(jiti@2.7.0))
vue-eslint-parser: 10.4.0(eslint@10.6.0(jiti@2.7.0))
xml-name-validator: 4.0.0
optionalDependencies:
'@stylistic/eslint-plugin': 5.10.0(eslint@10.5.0(jiti@2.7.0))
'@typescript-eslint/parser': 8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
'@stylistic/eslint-plugin': 5.10.0(eslint@10.6.0(jiti@2.7.0))
'@typescript-eslint/parser': 8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
eslint-plugin-wc@3.1.0(eslint@10.5.0(jiti@2.7.0)):
eslint-plugin-wc@3.1.0(eslint@10.6.0(jiti@2.7.0)):
dependencies:
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
is-valid-element-name: 1.0.0
js-levenshtein-esm: 2.0.0
@@ -6945,9 +6909,9 @@ snapshots:
eslint-visitor-keys@5.0.1: {}
eslint@10.5.0(jiti@2.7.0):
eslint@10.6.0(jiti@2.7.0):
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0(jiti@2.7.0))
'@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0))
'@eslint-community/regexpp': 4.12.2
'@eslint/config-array': 0.23.5
'@eslint/config-helpers': 0.6.0
@@ -7199,7 +7163,7 @@ snapshots:
happy-dom@20.10.6:
dependencies:
'@types/node': 25.9.4
'@types/node': 26.0.1
'@types/whatwg-mimetype': 3.0.2
'@types/ws': 8.18.1
buffer-image-size: 0.6.4
@@ -7486,7 +7450,7 @@ snapshots:
'@jest/fake-timers': 29.7.0
'@jest/types': 29.6.3
'@types/jsdom': 20.0.1
'@types/node': 25.9.4
'@types/node': 26.0.1
jest-mock: 29.7.0
jest-util: 29.7.0
jsdom: 20.0.3
@@ -7510,13 +7474,13 @@ snapshots:
jest-mock@29.7.0:
dependencies:
'@jest/types': 29.6.3
'@types/node': 25.9.4
'@types/node': 26.0.1
jest-util: 29.7.0
jest-util@29.7.0:
dependencies:
'@jest/types': 29.6.3
'@types/node': 25.9.4
'@types/node': 26.0.1
chalk: 4.1.2
ci-info: 3.9.0
graceful-fs: 4.2.11
@@ -7538,6 +7502,10 @@ snapshots:
dependencies:
argparse: 2.0.1
js-yaml@5.1.0:
dependencies:
argparse: 2.0.1
jsdoc-type-pratt-parser@7.2.0: {}
jsdom@20.0.3:
@@ -8860,13 +8828,13 @@ snapshots:
reflect.getprototypeof: 1.0.10
optional: true
typescript-eslint@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3):
typescript-eslint@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/parser': 8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/eslint-plugin': 8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/parser': 8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/typescript-estree': 8.62.0(typescript@6.0.3)
'@typescript-eslint/utils': 8.62.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
eslint: 10.5.0(jiti@2.7.0)
'@typescript-eslint/utils': 8.62.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)
eslint: 10.6.0(jiti@2.7.0)
typescript: 6.0.3
transitivePeerDependencies:
- supports-color
@@ -8887,7 +8855,7 @@ snapshots:
which-boxed-primitive: 1.1.1
optional: true
undici-types@7.24.6: {}
undici-types@8.3.0: {}
unicorn-magic@0.4.0: {}
@@ -8943,11 +8911,11 @@ snapshots:
vanilla-colorful@0.7.2: {}
vite-string-plugin@2.0.4(vite@8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)):
vite-string-plugin@2.0.4(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)):
dependencies:
vite: 8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)
vite: 8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)
vite@8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0):
vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0):
dependencies:
lightningcss: 1.32.0
picomatch: 4.0.4
@@ -8955,16 +8923,16 @@ snapshots:
rolldown: 1.1.3
tinyglobby: 0.2.17
optionalDependencies:
'@types/node': 25.9.4
'@types/node': 26.0.1
esbuild: 0.28.1
fsevents: 2.3.3
jiti: 2.7.0
yaml: 2.9.0
vitest@4.1.9(@types/node@25.9.4)(happy-dom@20.10.6)(jsdom@20.0.3)(vite@8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)):
vitest@4.1.9(@types/node@26.0.1)(happy-dom@20.10.6)(jsdom@20.0.3)(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)):
dependencies:
'@vitest/expect': 4.1.9
'@vitest/mocker': 4.1.9(vite@8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))
'@vitest/mocker': 4.1.9(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))
'@vitest/pretty-format': 4.1.9
'@vitest/runner': 4.1.9
'@vitest/snapshot': 4.1.9
@@ -8981,10 +8949,10 @@ snapshots:
tinyexec: 1.2.4
tinyglobby: 0.2.17
tinyrainbow: 3.1.0
vite: 8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)
vite: 8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 25.9.4
'@types/node': 26.0.1
happy-dom: 20.10.6
jsdom: 20.0.3
transitivePeerDependencies:
@@ -8992,21 +8960,15 @@ snapshots:
vscode-uri@3.1.0: {}
vue-bar-graph@2.2.0(typescript@6.0.3):
dependencies:
vue: 3.5.38(typescript@6.0.3)
transitivePeerDependencies:
- typescript
vue-chartjs@5.3.3(chart.js@4.5.1)(vue@3.5.38(typescript@6.0.3)):
dependencies:
chart.js: 4.5.1
vue: 3.5.38(typescript@6.0.3)
vue-eslint-parser@10.4.0(eslint@10.5.0(jiti@2.7.0)):
vue-eslint-parser@10.4.0(eslint@10.6.0(jiti@2.7.0)):
dependencies:
debug: 4.4.3
eslint: 10.5.0(jiti@2.7.0)
eslint: 10.6.0(jiti@2.7.0)
eslint-scope: 9.1.2
eslint-visitor-keys: 5.0.1
espree: 11.2.0
+14 -3
View File
@@ -73,7 +73,11 @@
"postUpdateOptions": ["gomodUpdateImportPaths"],
"postUpgradeTasks": {
"commands": ["make tidy"],
"fileFilters": ["go.mod", "go.sum", "assets/go-licenses.json"],
"fileFilters": [
"go.mod",
"go.sum",
"assets/go-licenses.json",
],
"executionMode": "branch",
},
},
@@ -95,8 +99,15 @@
"matchManagers": ["npm"],
"postUpdateOptions": ["pnpmDedupe"],
"postUpgradeTasks": {
"commands": ["make svg"],
"fileFilters": ["package.json", "pnpm-lock.yaml", "pnpm-workspace.yaml", "public/assets/img/svg/**", "options/fileicon/**"],
"commands": ["make svg", "make generate-codemirror-languages"],
"fileFilters": [
"package.json",
"pnpm-lock.yaml",
"pnpm-workspace.yaml",
"public/assets/img/svg/**",
"options/fileicon/**",
"assets/codemirror-languages.json",
],
"executionMode": "branch",
},
},
+21 -2
View File
@@ -258,8 +258,27 @@ func GetAllCommits(ctx *context.APIContext) {
ctx.APIErrorInternal(err)
return
} else if commitsCountTotal == 0 {
ctx.APIErrorNotFound()
return
// when date filters are active, a zero count may just mean no
// commits in the requested range — not that the path is invalid
if since == "" && until == "" {
ctx.APIErrorNotFound()
return
}
// verify the path actually exists in the revision history
totalWithoutDate, err := gitrepo.CommitsCount(ctx, ctx.Repo.Repository,
gitrepo.CommitsCountOptions{
Not: not,
Revision: []string{sha},
RelPath: []string{path},
})
if err != nil {
ctx.APIErrorInternal(err)
return
}
if totalWithoutDate == 0 {
ctx.APIErrorNotFound()
return
}
}
commits, _, err = ctx.Repo.GitRepo.CommitsByFileAndRange(
-7
View File
@@ -12,13 +12,6 @@ type swaggerResponseSecretList struct {
Body []api.Secret `json:"body"`
}
// Secret
// swagger:response Secret
type swaggerResponseSecret struct {
// in:body
Body api.Secret `json:"body"`
}
// ActionVariable
// swagger:response ActionVariable
type swaggerResponseActionVariable struct {
-7
View File
@@ -98,13 +98,6 @@ type swaggerIssueTemplates struct {
Body []api.IssueTemplate `json:"body"`
}
// StopWatch
// swagger:response StopWatch
type swaggerResponseStopWatch struct {
// in:body
Body api.StopWatch `json:"body"`
}
// StopWatchList
// swagger:response StopWatchList
type swaggerResponseStopWatchList struct {
-15
View File
@@ -1,15 +0,0 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package swagger
import (
api "gitea.dev/modules/structs"
)
// NodeInfo
// swagger:response NodeInfo
type swaggerResponseNodeInfo struct {
// in:body
Body api.NodeInfo `json:"body"`
}
+8 -4
View File
@@ -8,11 +8,12 @@ import (
"gitea.dev/services/forms"
)
// not actually a response, just a hack to get go-swagger to include definitions
// of the various XYZOption structs
// not actually a set of parameters, just a hack to get go-swagger to include
// definitions of the various XYZOption structs. The annotation below uses an
// operation id that matches no route, so the spec carries no unused response
// or parameter for it while still emitting the referenced definitions.
// parameterBodies
// swagger:response parameterBodies
// swagger:parameters parameterBodies
type swaggerParameterBodies struct {
// in:body
AddCollaboratorOption api.AddCollaboratorOption
@@ -235,4 +236,7 @@ type swaggerParameterBodies struct {
// in:body
LockIssueOption api.LockIssueOption
// in:body
MergeUpstreamRequest api.MergeUpstreamRequest
}
-13
View File
@@ -84,13 +84,6 @@ type swaggerResponseTagProtection struct {
Body api.TagProtection `json:"body"`
}
// Reference
// swagger:response Reference
type swaggerResponseReference struct {
// in:body
Body api.Reference `json:"body"`
}
// ReferenceList
// swagger:response ReferenceList
type swaggerResponseReferenceList struct {
@@ -511,12 +504,6 @@ type swaggerCompare struct {
Body api.Compare `json:"body"`
}
// swagger:response MergeUpstreamRequest
type swaggerMergeUpstreamRequest struct {
// in:body
Body api.MergeUpstreamRequest `json:"body"`
}
// swagger:response MergeUpstreamResponse
type swaggerMergeUpstreamResponse struct {
// in:body
+3
View File
@@ -147,6 +147,9 @@ func MustInitSessioner() func(next http.Handler) http.Handler {
Secure: setting.SessionConfig.Secure,
SameSite: setting.SessionConfig.SameSite,
Domain: setting.SessionConfig.Domain,
// in the future, if websocket is used, the websocket handler should manage its own session sync (release)
IgnoreReleaseForWebSocket: true,
})
if err != nil {
log.Fatal("common.Sessioner failed: %v", err)
+8 -32
View File
@@ -31,9 +31,7 @@ import (
type preReceiveContext struct {
*gitea_context.PrivateContext
// loadedPusher indicates that where the following information are loaded
loadedPusher bool
user *user_model.User // it's the org user if a DeployKey is used
user *user_model.User // the "pusher", it's the org user if a DeployKey is used
userPerm access_model.Permission
deployKeyAccessMode perm_model.AccessMode
@@ -53,10 +51,7 @@ type preReceiveContext struct {
func (ctx *preReceiveContext) canWriteCodeUnit() bool {
if ctx.canWriteCodeUnitCached == nil {
var canWrite bool
if ctx.loadPusherAndPermission() {
canWrite = ctx.userPerm.CanWrite(unit.TypeCode) || ctx.deployKeyAccessMode >= perm_model.AccessModeWrite
}
canWrite := ctx.userPerm.CanWrite(unit.TypeCode) || ctx.deployKeyAccessMode >= perm_model.AccessModeWrite
ctx.canWriteCodeUnitCached = &canWrite
}
return *ctx.canWriteCodeUnitCached
@@ -91,9 +86,6 @@ func (ctx *preReceiveContext) assertCanWriteRef(refFullName git.RefName) bool {
// CanCreatePullRequest returns true if pusher can create pull requests
func (ctx *preReceiveContext) CanCreatePullRequest() bool {
if !ctx.checkedCanCreatePullRequest {
if !ctx.loadPusherAndPermission() {
return false
}
ctx.canCreatePullRequest = ctx.userPerm.CanRead(unit.TypePullRequests)
ctx.checkedCanCreatePullRequest = true
}
@@ -124,6 +116,10 @@ func HookPreReceive(ctx *gitea_context.PrivateContext) {
opts: opts,
}
if !ourCtx.loadPusherAndPermission() {
return // if error occurs, loadPusherAndPermission had written the error response
}
// Iterate across the provided old commit IDs
for i := range opts.OldCommitIDs {
oldCommitID := opts.OldCommitIDs[i]
@@ -281,18 +277,10 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
canPush = !changedProtectedfiles && protectBranch.CanPush && (!protectBranch.EnableWhitelist || protectBranch.WhitelistDeployKeys)
}
} else {
user, err := user_model.GetUserByID(ctx, ctx.opts.UserID)
if err != nil {
log.Error("Unable to GetUserByID for commits from %s to %s in %-v: %v", oldCommitID, newCommitID, repo, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Unable to GetUserByID for commits from %s to %s: %v", oldCommitID, newCommitID, err),
})
return
}
if isForcePush {
canPush = !changedProtectedfiles && protectBranch.CanUserForcePush(ctx, user)
canPush = !changedProtectedfiles && protectBranch.CanUserForcePush(ctx, ctx.user)
} else {
canPush = !changedProtectedfiles && protectBranch.CanUserPush(ctx, user)
canPush = !changedProtectedfiles && protectBranch.CanUserPush(ctx, ctx.user)
}
}
@@ -354,12 +342,6 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
return
}
// although we should have called `loadPusherAndPermission` before, here we call it explicitly again because we need to access ctx.user below
if !ctx.loadPusherAndPermission() {
// if error occurs, loadPusherAndPermission had written the error response
return
}
// Now check if the user is allowed to merge PRs for this repository
// Note: we can use ctx.perm and ctx.user directly as they will have been loaded above
allowedMerge, err := pull_service.IsUserAllowedToMerge(ctx, pr, ctx.userPerm, ctx.user)
@@ -499,10 +481,6 @@ func generateGitEnv(opts *private.HookOptions) (env []string) {
// loadPusherAndPermission returns false if an error occurs, and it writes the error response
func (ctx *preReceiveContext) loadPusherAndPermission() bool {
if ctx.loadedPusher {
return true
}
if ctx.opts.UserID == user_model.ActionsUserID {
taskID := ctx.opts.ActionsTaskID
ctx.user = user_model.NewActionsUserWithTaskID(taskID)
@@ -555,7 +533,5 @@ func (ctx *preReceiveContext) loadPusherAndPermission() bool {
}
ctx.deployKeyAccessMode = deployKey.Mode
}
ctx.loadedPusher = true
return true
}
-1
View File
@@ -52,7 +52,6 @@ func TestPreReceiveCanWriteCodePerBranch(t *testing.T) {
mockCtx, _ := contexttest.MockPrivateContext(t, "/")
ctx := &preReceiveContext{
PrivateContext: mockCtx,
loadedPusher: true,
user: maintainer,
userPerm: headPerm,
}
+2 -20
View File
@@ -450,27 +450,9 @@ func EditUserPost(ctx *context.Context) {
log.Trace("Account profile updated by admin (%s): %s", ctx.Doer.Name, u.Name)
if form.Reset2FA {
tf, err := auth.GetTwoFactorByUID(ctx, u.ID)
if err != nil && !auth.IsErrTwoFactorNotEnrolled(err) {
ctx.ServerError("auth.GetTwoFactorByUID", err)
if _, _, err := auth.DisableTwoFactor(ctx, u.ID); err != nil {
ctx.ServerError("auth.DisableTwoFactor", err)
return
} else if tf != nil {
if err := auth.DeleteTwoFactorByID(ctx, tf.ID, u.ID); err != nil {
ctx.ServerError("auth.DeleteTwoFactorByID", err)
return
}
}
wn, err := auth.GetWebAuthnCredentialsByUID(ctx, u.ID)
if err != nil {
ctx.ServerError("auth.GetTwoFactorByUID", err)
return
}
for _, cred := range wn {
if _, err := auth.DeleteCredential(ctx, cred.ID, u.ID); err != nil {
ctx.ServerError("auth.DeleteCredential", err)
return
}
}
}
+5 -5
View File
@@ -118,7 +118,7 @@ func autoSignIn(ctx *context.Context) (bool, error) {
ctx.SetSiteCookie(setting.CookieRememberName, nt.ID+":"+token, setting.LogInRememberDays*timeutil.Day)
if err := updateSession(ctx, nil, map[string]any{
if err := regenerateSession(ctx, nil, map[string]any{
session.KeyUID: u.ID,
session.KeyUname: u.Name,
session.KeyUserHasTwoFactorAuth: userHasTwoFactorAuth,
@@ -357,7 +357,7 @@ func SignInPost(ctx *context.Context) {
// User will need to use WebAuthn, save data
updates["totpEnrolled"] = u.ID
}
if err := updateSession(ctx, nil, updates); err != nil {
if err := regenerateSession(ctx, nil, updates); err != nil {
ctx.ServerError("UserSignIn: Unable to update session", err)
return
}
@@ -398,7 +398,7 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember bool) {
return
}
if err := updateSession(ctx, []string{
if err := regenerateSession(ctx, []string{
// Delete the openid, 2fa and link_account data
"openid_verified_uri",
"openid_signin_remember",
@@ -884,7 +884,7 @@ func handleAccountActivation(ctx *context.Context, user *user_model.User) {
log.Trace("User activated: %s", user.Name)
if err := updateSession(ctx, nil, map[string]any{
if err := regenerateSession(ctx, nil, map[string]any{
"uid": user.ID,
"uname": user.Name,
}); err != nil {
@@ -936,7 +936,7 @@ func ActivateEmail(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
}
func updateSession(ctx *context.Context, deletes []string, updates map[string]any) error {
func regenerateSession(ctx *context.Context, deletes []string, updates map[string]any) error {
if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil {
return fmt.Errorf("regenerate session: %w", err)
}
+6 -1
View File
@@ -164,7 +164,12 @@ func oauth2LinkAccount(ctx *context.Context, u *user_model.User, linkAccountData
return
}
if err := updateSession(ctx, nil, map[string]any{
if err := Oauth2SetLinkAccountData(ctx, *linkAccountData); err != nil {
ctx.ServerError("Oauth2SetLinkAccountData", err)
return
}
if err := regenerateSession(ctx, nil, map[string]any{
// User needs to use 2FA, save data and redirect to 2FA page.
"twofaUid": u.ID,
"twofaRemember": remember,
+3 -5
View File
@@ -285,9 +285,7 @@ func oauth2GetLinkAccountData(ctx *context.Context) *LinkAccountData {
}
func Oauth2SetLinkAccountData(ctx *context.Context, linkAccountData LinkAccountData) error {
return updateSession(ctx, nil, map[string]any{
"linkAccountData": linkAccountData,
})
return ctx.Session.Set("linkAccountData", linkAccountData)
}
func showLinkingLogin(ctx *context.Context, authSourceID int64, gothUser goth.User) {
@@ -409,7 +407,7 @@ func handleOAuth2SignIn(ctx *context.Context, authSource *auth.Source, u *user_m
return
}
if err := updateSession(ctx, nil, map[string]any{
if err := regenerateSession(ctx, nil, map[string]any{
session.KeyUID: u.ID,
session.KeyUname: u.Name,
session.KeyUserHasTwoFactorAuth: userHasTwoFactorAuth,
@@ -434,7 +432,7 @@ func handleOAuth2SignIn(ctx *context.Context, authSource *auth.Source, u *user_m
}
}
if err := updateSession(ctx, nil, map[string]any{
if err := regenerateSession(ctx, nil, map[string]any{
// User needs to use 2FA, save data and redirect to 2FA page.
"twofaUid": u.ID,
"twofaRemember": false,
+1 -1
View File
@@ -213,7 +213,7 @@ func signInOpenIDVerify(ctx *context.Context) {
if u != nil {
nickname = u.LowerName
}
if err := updateSession(ctx, nil, map[string]any{
if err := regenerateSession(ctx, nil, map[string]any{
"openid_verified_uri": id,
"openid_determined_email": email,
"openid_determined_username": nickname,
+63 -4
View File
@@ -14,8 +14,10 @@ import (
repo_model "gitea.dev/models/repo"
user_model "gitea.dev/models/user"
actions_module "gitea.dev/modules/actions"
"gitea.dev/modules/actions/jobparser"
"gitea.dev/modules/commitstatus"
"gitea.dev/modules/log"
api "gitea.dev/modules/structs"
"gitea.dev/modules/util"
webhook_module "gitea.dev/modules/webhook"
commitstatus_service "gitea.dev/services/repository/commitstatus"
@@ -147,21 +149,78 @@ func createCommitStatus(ctx context.Context, repo *repo_model.Repository, event,
// scopedPrefix is computed once per run by the caller. The settings page derives the same string to preview expected checks.
ctxName = actions_module.ScopedWorkflowStatusContextName(scopedPrefix, displayName, job.Name, event)
}
targetURL := fmt.Sprintf("%s/jobs/%d", run.Link(), job.ID)
return createWorkflowCommitStatus(ctx, repo, commitID, ctxName, run.WorkflowID, toCommitStatus(job.Status), targetURL, toCommitStatusDescription(job))
}
// CreateSkippedCommitStatusForFilteredWorkflow posts a skipped commit status for each job of a
// workflow that matched the triggering event but was excluded by a branch/paths filter.
// This lets a required status check tied to that context be satisfied without the workflow running.
// No ActionRun is created, so the status has no target URL (there is no run/job to link to).
// A non-empty scopedPrefix prefixes each context with its source repo, matching scoped runs.
func CreateSkippedCommitStatusForFilteredWorkflow(ctx context.Context, repo *repo_model.Repository, event webhook_module.HookEventType, triggerEvent, workflowID string, content []byte, payload api.Payloader, scopedPrefix string) error {
// Derive the status event name and target commit from the payload.
// TODO: this mirrors getCommitStatusEventNameAndCommitID, which derives the same from a persisted run. Should merge the logic if possible.
var statusEvent, commitID string
switch event {
case webhook_module.HookEventPush:
if p, ok := payload.(*api.PushPayload); ok && p.HeadCommit != nil {
statusEvent, commitID = "push", p.HeadCommit.ID
}
case webhook_module.HookEventPullRequest,
webhook_module.HookEventPullRequestSync,
webhook_module.HookEventPullRequestAssign,
webhook_module.HookEventPullRequestLabel,
webhook_module.HookEventPullRequestReviewRequest,
webhook_module.HookEventPullRequestMilestone:
if p, ok := payload.(*api.PullRequestPayload); ok && p.PullRequest != nil && p.PullRequest.Head != nil {
statusEvent, commitID = "pull_request", p.PullRequest.Head.Sha
if triggerEvent == actions_module.GithubEventPullRequestTarget {
statusEvent = "pull_request_target"
}
}
}
if statusEvent == "" || commitID == "" {
return nil // unsupported event or missing commit id, nothing to post
}
workflows, err := jobparser.Parse(content)
if err != nil {
return fmt.Errorf("jobparser.Parse: %w", err)
}
displayName := actions_module.WorkflowDisplayName(workflowID, content)
for _, sw := range workflows {
_, job := sw.Job()
if job == nil {
continue
}
jobName := util.EllipsisDisplayString(job.Name, 255) // run creation truncates job names the same way
ctxName := actions_module.WorkflowStatusContextName(displayName, jobName, statusEvent)
if scopedPrefix != "" {
ctxName = actions_module.ScopedWorkflowStatusContextName(scopedPrefix, displayName, jobName, statusEvent)
}
// "Skipped" mirrors toCommitStatusDescription for StatusSkipped.
if err := createWorkflowCommitStatus(ctx, repo, commitID, ctxName, workflowID, commitstatus.CommitStatusSkipped, "", "Skipped"); err != nil {
return err
}
}
return nil
}
// createWorkflowCommitStatus posts the commit status for one workflow-job context.
func createWorkflowCommitStatus(ctx context.Context, repo *repo_model.Repository, commitID, ctxName, workflowID string, state commitstatus.CommitStatusState, targetURL, description string) error {
// Mix the workflow file path into the hash so two workflow files that
// share the same `name:` and job name produce distinct commit statuses
// even though they render identically — matching GitHub's behavior
// (issue #35699).
ctxHash := git_model.HashCommitStatusContext(ctxName + "\x00" + run.WorkflowID)
ctxHash := git_model.HashCommitStatusContext(ctxName + "\x00" + workflowID)
// Pre-fix rows were hashed from Context alone. If a pre-existing row with
// the legacy hash is still the "latest" for this SHA, reuse that hash so
// the new row supersedes it; otherwise the old pending status would stay
// stuck forever (it lives in its own dedupe group). Only relevant for
// in-flight workflows at upgrade time.
legacyHash := git_model.HashCommitStatusContext(ctxName)
state := toCommitStatus(job.Status)
targetURL := fmt.Sprintf("%s/jobs/%d", run.Link(), job.ID)
description := toCommitStatusDescription(job)
statuses, err := git_model.GetLatestCommitStatus(ctx, repo.ID, commitID, db.ListOptionsAll)
if err != nil {
+61 -7
View File
@@ -183,8 +183,9 @@ func notify(ctx context.Context, input *notifyInput) error {
}
var detectedWorkflows []*actions_module.DetectedWorkflow
var filteredWorkflows []*actions_module.DetectedWorkflow
actionsConfig := input.Repo.MustGetUnit(ctx, unit_model.TypeActions).ActionsConfig()
workflows, schedules, err := actions_module.DetectWorkflows(gitRepo, commit,
workflows, schedules, filtered, err := actions_module.DetectWorkflows(gitRepo, commit,
input.Event,
input.Payload,
shouldDetectSchedules,
@@ -212,6 +213,17 @@ func notify(ctx context.Context, input *notifyInput) error {
}
}
for _, wf := range filtered {
if actionsConfig.IsWorkflowDisabled(wf.EntryName) {
log.Trace("repo %s has disable workflows %s", input.Repo.RelativePath(), wf.EntryName)
continue
}
if wf.TriggerEvent.Name != actions_module.GithubEventPullRequestTarget {
filteredWorkflows = append(filteredWorkflows, wf)
}
}
if input.PullRequest != nil {
// detect pull_request_target workflows
baseRef := git.BranchPrefix + input.PullRequest.BaseBranch
@@ -219,7 +231,7 @@ func notify(ctx context.Context, input *notifyInput) error {
if err != nil {
return fmt.Errorf("gitRepo.GetCommit: %w", err)
}
baseWorkflows, _, err := actions_module.DetectWorkflows(gitRepo, baseCommit, input.Event, input.Payload, false)
baseWorkflows, _, baseFiltered, err := actions_module.DetectWorkflows(gitRepo, baseCommit, input.Event, input.Payload, false)
if err != nil {
return fmt.Errorf("DetectWorkflows: %w", err)
}
@@ -227,11 +239,24 @@ func notify(ctx context.Context, input *notifyInput) error {
log.Trace("repo %s with commit %s couldn't find pull_request_target workflows", input.Repo.RelativePath(), baseCommit.ID)
} else {
for _, wf := range baseWorkflows {
if actionsConfig.IsWorkflowDisabled(wf.EntryName) {
log.Trace("repo %s has disable workflows %s", input.Repo.RelativePath(), wf.EntryName)
continue
}
if wf.TriggerEvent.Name == actions_module.GithubEventPullRequestTarget {
detectedWorkflows = append(detectedWorkflows, wf)
}
}
}
for _, wf := range baseFiltered {
if actionsConfig.IsWorkflowDisabled(wf.EntryName) {
log.Trace("repo %s has disable workflows %s", input.Repo.RelativePath(), wf.EntryName)
continue
}
if wf.TriggerEvent.Name == actions_module.GithubEventPullRequestTarget {
filteredWorkflows = append(filteredWorkflows, wf)
}
}
}
if shouldDetectSchedules {
@@ -244,6 +269,8 @@ func notify(ctx context.Context, input *notifyInput) error {
return err
}
handleFilteredWorkflows(ctx, input, filteredWorkflows)
return detectAndHandleScopedWorkflows(ctx, input, ref, gitRepo, commit)
}
@@ -369,6 +396,16 @@ func buildApproveAndInsertRun(
return nil
}
// handleFilteredWorkflows posts a skipped commit status for each workflow that matched the event but was excluded by a branch/paths filter.
func handleFilteredWorkflows(ctx context.Context, input *notifyInput, filteredWorkflows []*actions_module.DetectedWorkflow) {
for _, dwf := range filteredWorkflows {
if err := CreateSkippedCommitStatusForFilteredWorkflow(ctx, input.Repo, input.Event, dwf.TriggerEvent.Name, dwf.EntryName, dwf.Content, input.Payload, ""); err != nil {
log.Error("repo %s: skipped commit status for workflow %s: %v", input.Repo.RelativePath(), dwf.EntryName, err)
continue
}
}
}
func newNotifyInputFromIssue(issue *issues_model.Issue, event webhook_module.HookEventType) *notifyInput {
return newNotifyInput(issue.Repo, issue.Poster, event)
}
@@ -640,7 +677,7 @@ func detectAndHandleScopedWorkflows(
continue
}
sourceCommitSHA, detected, err := detectScopedWorkflowsForSource(ctx, input, consumerGitRepo, consumerCommit, sourceRepo)
sourceCommitSHA, detected, filtered, err := detectScopedWorkflowsForSource(ctx, input, consumerGitRepo, consumerCommit, sourceRepo)
if err != nil {
log.Error("scoped workflows: source %d for consumer %s: %v", sourceRepoID, input.Repo.RelativePath(), err)
continue
@@ -658,23 +695,40 @@ func detectAndHandleScopedWorkflows(
continue
}
}
// A filtered-out scoped workflow posts a skipped commit status.
if len(filtered) > 0 {
scopedPrefix := actions_model.ScopedStatusContextPrefix(ctx, sourceRepo.ID)
for _, dwf := range filtered {
if actions_model.ScopedWorkflowOptedOut(actionsConfig, sources, sourceRepo.ID, dwf.EntryName) {
continue
}
if err := CreateSkippedCommitStatusForFilteredWorkflow(ctx, input.Repo, input.Event, dwf.TriggerEvent.Name, dwf.EntryName, dwf.Content, input.Payload, scopedPrefix); err != nil {
log.Error("scoped workflows: skipped commit status for source %s workflow %s: %v", sourceRepo.RelativePath(), dwf.EntryName, err)
continue
}
}
}
}
return nil
}
// detectScopedWorkflowsForSource detects the scoped workflows from the source repo at its default branch
// detectScopedWorkflowsForSource detects the scoped workflows from the source repo at its default branch.
// detected are the workflows to run; filtered matched the event but were excluded by a branch/paths
// filter and post a skipped commit status.
func detectScopedWorkflowsForSource(
ctx context.Context,
input *notifyInput,
consumerGitRepo *git.Repository,
consumerCommit *git.Commit,
sourceRepo *repo_model.Repository,
) (sourceCommitSHA string, detected []*actions_module.DetectedWorkflow, err error) {
) (sourceCommitSHA string, detected, filtered []*actions_module.DetectedWorkflow, err error) {
// scoped workflow content is always taken from the source repo's default branch; the parse is cached per (source, default-branch SHA) and reused across consuming repos/events
sourceCommitSHA, parsed, err := LoadParsedScopedWorkflows(ctx, sourceRepo)
if err != nil {
return "", nil, err
return "", nil, nil, err
}
return sourceCommitSHA, actions_module.MatchScopedWorkflows(parsed, consumerGitRepo, consumerCommit, input.Event, input.Payload), nil
detected, filtered = actions_module.MatchScopedWorkflows(parsed, consumerGitRepo, consumerCommit, input.Event, input.Payload)
return sourceCommitSHA, detected, filtered, nil
}
-4
View File
@@ -104,10 +104,6 @@ type APINotFound struct{}
// swagger:response conflict
type APIConflict struct{}
// APIRedirect is a redirect response
// swagger:response redirect
type APIRedirect struct{}
// APIString is a string response
// swagger:response string
type APIString string
+44 -6
View File
@@ -42,6 +42,38 @@ type ArchiveRequest struct {
archiveRefShortName string // the ref short name to download the archive, for example: "master", "v1.0.0", "commit id"
}
type archiveQueueItem struct {
RepoID int64 `json:"RepoID"`
Type repo_model.ArchiveType `json:"Type"`
CommitID string `json:"CommitID"`
Paths []string `json:"Paths,omitempty"`
ArchiveRefShortName string `json:"ArchiveRefShortName,omitempty"`
}
func (aReq *ArchiveRequest) toQueueItem() *archiveQueueItem {
return &archiveQueueItem{
RepoID: aReq.Repo.ID,
Type: aReq.Type,
CommitID: aReq.CommitID,
Paths: aReq.Paths,
ArchiveRefShortName: aReq.archiveRefShortName,
}
}
func (item *archiveQueueItem) toArchiveRequest(ctx context.Context) (*ArchiveRequest, error) {
repo, err := repo_model.GetRepositoryByID(ctx, item.RepoID)
if err != nil {
return nil, err
}
return &ArchiveRequest{
Repo: repo,
Type: item.Type,
CommitID: item.CommitID,
Paths: item.Paths,
archiveRefShortName: item.ArchiveRefShortName,
}, nil
}
// NewRequest creates an archival request, based on the URI. The
// resulting ArchiveRequest is suitable for being passed to Await()
// if it's determined that the request still needs to be satisfied.
@@ -227,13 +259,18 @@ func doArchive(ctx context.Context, r *ArchiveRequest) (*repo_model.RepoArchiver
return archiver, nil
}
var archiverQueue *queue.WorkerPoolQueue[*ArchiveRequest]
var archiverQueue *queue.WorkerPoolQueue[*archiveQueueItem]
// Init initializes archiver
func Init(ctx context.Context) error {
handler := func(items ...*ArchiveRequest) []*ArchiveRequest {
for _, archiveReq := range items {
log.Trace("ArchiverData Process: %#v", archiveReq)
handler := func(items ...*archiveQueueItem) []*archiveQueueItem {
for _, item := range items {
log.Trace("ArchiverData Process: %#v", item)
archiveReq, err := item.toArchiveRequest(ctx)
if err != nil {
log.Error("Archive repo %d: %v", item.RepoID, err)
continue
}
if archiver, err := doArchive(ctx, archiveReq); err != nil {
log.Error("Archive %v failed: %v", archiveReq, err)
} else {
@@ -254,14 +291,15 @@ func Init(ctx context.Context) error {
// StartArchive push the archive request to the queue
func StartArchive(request *ArchiveRequest) error {
has, err := archiverQueue.Has(request)
item := request.toQueueItem()
has, err := archiverQueue.Has(item)
if err != nil {
return err
}
if has {
return nil
}
return archiverQueue.Push(request)
return archiverQueue.Push(item)
}
func deleteOldRepoArchiver(ctx context.Context, archiver *repo_model.RepoArchiver) error {
@@ -7,7 +7,9 @@ import (
"testing"
"time"
repo_model "gitea.dev/models/repo"
"gitea.dev/models/unittest"
"gitea.dev/modules/json"
"gitea.dev/modules/util"
"gitea.dev/services/contexttest"
@@ -21,6 +23,22 @@ func TestMain(m *testing.M) {
unittest.MainTest(m)
}
func TestArchiveQueueItemJSON(t *testing.T) {
orig := &archiveQueueItem{
RepoID: 7,
Type: repo_model.ArchiveZip,
CommitID: "abc123",
Paths: []string{"agents"},
ArchiveRefShortName: "main",
}
bs, err := json.Marshal(orig)
require.NoError(t, err)
var decoded archiveQueueItem
require.NoError(t, json.Unmarshal(bs, &decoded))
assert.Equal(t, *orig, decoded)
}
func TestArchive_Basic(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
-3
View File
@@ -12,9 +12,6 @@ base: core24
adopt-info: gitea
platforms:
armhf:
build-on: [armhf]
build-for: [armhf]
amd64:
build-on: [amd64]
build-for: [amd64]
+1 -1
View File
@@ -105,7 +105,7 @@
<strong class="tw-text-red">{{ctx.Locale.TrN .Activity.Code.Deletions "repo.activity.git_stats_deletion_1" "repo.activity.git_stats_deletion_n" .Activity.Code.Deletions}}</strong>.
</div>
<div class="ui attached segment">
<div id="repo-activity-top-authors-chart"></div>
<div id="repo-activity-top-authors-chart" class="tw-h-[100px]"></div>
</div>
</div>
{{end}}
+80 -205
View File
@@ -22762,7 +22762,7 @@
"type": "object",
"properties": {
"permission": {
"description": "Permission level to grant the collaborator\nread RepoWritePermissionRead\nwrite RepoWritePermissionWrite\nadmin RepoWritePermissionAdmin",
"description": "Permission level to grant the collaborator",
"type": "string",
"enum": [
"read",
@@ -22917,6 +22917,7 @@
"x-go-name": "DownloadURL"
},
"created_at": {
"description": "Created is the time when the attachment was uploaded",
"type": "string",
"format": "date-time",
"x-go-name": "Created"
@@ -23065,8 +23066,8 @@
"x-go-name": "BlockOnRejectedReviews"
},
"branch_name": {
"description": "Deprecated: true",
"type": "string",
"x-deprecated": true,
"x-go-name": "BranchName"
},
"bypass_allowlist_teams": {
@@ -23389,7 +23390,7 @@
"x-go-name": "SHA"
},
"state": {
"description": "State is the overall combined status state\npending CommitStatusPending is for when the CommitStatus is Pending\nsuccess CommitStatusSuccess is for when the CommitStatus is Success\nerror CommitStatusError is for when the CommitStatus is Error\nfailure CommitStatusFailure is for when the CommitStatus is Failure\nwarning CommitStatusWarning is for when the CommitStatus is Warning\nskipped CommitStatusSkipped is for when CommitStatus is Skipped",
"description": "State is the overall combined status state",
"type": "string",
"enum": [
"pending",
@@ -23503,6 +23504,7 @@
"$ref": "#/definitions/User"
},
"created": {
"description": "Created is the time when the commit was created",
"type": "string",
"format": "date-time",
"x-go-name": "Created"
@@ -23566,11 +23568,13 @@
"type": "object",
"properties": {
"author": {
"description": "Author is the author date for the commit",
"type": "string",
"format": "date-time",
"x-go-name": "Author"
},
"committer": {
"description": "Committer is the committer date for the commit",
"type": "string",
"format": "date-time",
"x-go-name": "Committer"
@@ -23583,6 +23587,7 @@
"title": "CommitMeta contains meta information of a commit in terms of API.",
"properties": {
"created": {
"description": "Created is the time when the commit was created",
"type": "string",
"format": "date-time",
"x-go-name": "Created"
@@ -23654,7 +23659,7 @@
"x-go-name": "ID"
},
"status": {
"description": "State represents the status state (pending, success, error, failure)\npending CommitStatusPending is for when the CommitStatus is Pending\nsuccess CommitStatusSuccess is for when the CommitStatus is Success\nerror CommitStatusError is for when the CommitStatus is Error\nfailure CommitStatusFailure is for when the CommitStatus is Failure\nwarning CommitStatusWarning is for when the CommitStatus is Warning\nskipped CommitStatusSkipped is for when CommitStatus is Skipped",
"description": "State represents the status state (pending, success, error, failure)",
"type": "string",
"enum": [
"pending",
@@ -23695,6 +23700,7 @@
"x-go-name": "Date"
},
"email": {
"description": "Email is the person's email address",
"type": "string",
"format": "email",
"x-go-name": "Email"
@@ -23939,8 +23945,8 @@
"x-go-name": "BlockOnRejectedReviews"
},
"branch_name": {
"description": "Deprecated: true",
"type": "string",
"x-deprecated": true,
"x-go-name": "BranchName"
},
"bypass_allowlist_teams": {
@@ -24097,9 +24103,10 @@
"x-go-name": "BranchName"
},
"old_branch_name": {
"description": "Deprecated: true\nName of the old branch to create from",
"description": "Name of the old branch to create from",
"type": "string",
"uniqueItems": true,
"x-deprecated": true,
"x-go-name": "OldBranchName"
},
"old_ref_name": {
@@ -24222,6 +24229,7 @@
],
"properties": {
"active": {
"description": "Whether the webhook should be active upon creation",
"type": "boolean",
"default": false,
"x-go-name": "Active"
@@ -24253,6 +24261,7 @@
"x-go-name": "Name"
},
"type": {
"description": "The type of the webhook to create",
"type": "string",
"enum": [
"dingtalk",
@@ -24287,6 +24296,7 @@
],
"properties": {
"body": {
"description": "Body is the comment text content",
"type": "string",
"x-go-name": "Body"
}
@@ -24417,6 +24427,7 @@
"example": false
},
"name": {
"description": "Name is the display name for the new label",
"type": "string",
"x-go-name": "Name"
}
@@ -24433,11 +24444,13 @@
"x-go-name": "Description"
},
"due_on": {
"description": "Deadline is the due date for the milestone",
"type": "string",
"format": "date-time",
"x-go-name": "Deadline"
},
"state": {
"description": "State indicates the initial state of the milestone",
"type": "string",
"enum": [
"open",
@@ -24541,7 +24554,7 @@
"x-go-name": "UserName"
},
"visibility": {
"description": "possible values are `public` (default), `limited` or `private`\npublic UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate",
"description": "possible values are `public` (default), `limited` or `private`",
"type": "string",
"enum": [
"public",
@@ -24833,7 +24846,7 @@
"x-go-name": "Name"
},
"object_format_name": {
"description": "ObjectFormatName of the underlying git repository, empty string for default (sha1)\nsha1 ObjectFormatSHA1\nsha256 ObjectFormatSHA256",
"description": "ObjectFormatName of the underlying git repository, empty string for default (sha1)",
"type": "string",
"enum": [
"sha1",
@@ -24886,7 +24899,7 @@
"x-go-name": "Description"
},
"state": {
"description": "State represents the status state to set (pending, success, error, failure)\npending CommitStatusPending is for when the CommitStatus is Pending\nsuccess CommitStatusSuccess is for when the CommitStatus is Success\nerror CommitStatusError is for when the CommitStatus is Error\nfailure CommitStatusFailure is for when the CommitStatus is Failure\nwarning CommitStatusWarning is for when the CommitStatus is Warning\nskipped CommitStatusSkipped is for when CommitStatus is Skipped",
"description": "State represents the status state to set (pending, success, error, failure)",
"type": "string",
"enum": [
"pending",
@@ -24920,6 +24933,7 @@
"x-go-name": "Message"
},
"tag_name": {
"description": "The name of the tag to create",
"type": "string",
"x-go-name": "TagName"
},
@@ -24996,18 +25010,20 @@
"x-go-name": "Permission"
},
"units": {
"description": "Deprecated: This variable should be replaced by UnitsMap and will be dropped in later versions.",
"type": "array",
"items": {
"type": "string"
},
"x-deprecated": true,
"x-go-name": "Units",
"example": [
"repo.actions",
"repo.packages",
"repo.code",
"repo.issues",
"repo.ext_issues",
"repo.wiki",
"repo.ext_wiki",
"repo.pulls",
"repo.releases",
"repo.projects",
@@ -25020,10 +25036,21 @@
"type": "string"
},
"x-go-name": "UnitsMap",
"example": "{\"repo.actions\",\"repo.packages\",\"repo.code\":\"read\",\"repo.issues\":\"write\",\"repo.ext_issues\":\"none\",\"repo.wiki\":\"admin\",\"repo.pulls\":\"owner\",\"repo.releases\":\"none\",\"repo.projects\":\"none\",\"repo.ext_wiki\":\"none\"}"
"example": {
"repo.actions": "read",
"repo.code": "read",
"repo.ext_issues": "none",
"repo.ext_wiki": "none",
"repo.issues": "write",
"repo.packages": "read",
"repo.projects": "none",
"repo.pulls": "owner",
"repo.releases": "none",
"repo.wiki": "admin"
}
},
"visibility": {
"description": "Team visibility within the organization. Defaults to \"private\".\npublic TeamVisibilityPublic\nlimited TeamVisibilityLimited\nprivate TeamVisibilityPrivate",
"description": "Team visibility within the organization. Defaults to \"private\".",
"type": "string",
"enum": [
"public",
@@ -25052,7 +25079,6 @@
},
"email": {
"type": "string",
"format": "email",
"x-go-name": "Email"
},
"full_name": {
@@ -25098,7 +25124,7 @@
"x-go-name": "Username"
},
"visibility": {
"description": "User visibility level: public, limited, or private\npublic UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate",
"description": "User visibility level: public, limited, or private",
"type": "string",
"enum": [
"public",
@@ -25298,6 +25324,7 @@
"type": "object",
"properties": {
"created_at": {
"description": "Created is the time when the deploy key was added",
"type": "string",
"format": "date-time",
"x-go-name": "Created"
@@ -25634,6 +25661,7 @@
],
"properties": {
"body": {
"description": "Body is the updated comment text content",
"type": "string",
"x-go-name": "Body"
}
@@ -25798,7 +25826,7 @@
"x-go-name": "RepoAdminChangeTeamAccess"
},
"visibility": {
"description": "possible values are `public`, `limited` or `private`\npublic UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate",
"description": "possible values are `public`, `limited` or `private`",
"type": "string",
"enum": [
"public",
@@ -26198,10 +26226,12 @@
"x-go-name": "Permission"
},
"units": {
"description": "Deprecated: This variable should be replaced by UnitsMap and will be dropped in later versions.",
"type": "array",
"items": {
"type": "string"
},
"x-deprecated": true,
"x-go-name": "Units",
"example": [
"repo.code",
@@ -26232,7 +26262,7 @@
}
},
"visibility": {
"description": "Team visibility within the organization. When omitted, visibility is\nleft unchanged.\npublic TeamVisibilityPublic\nlimited TeamVisibilityLimited\nprivate TeamVisibilityPrivate",
"description": "Team visibility within the organization. When omitted, visibility is\nleft unchanged.",
"type": "string",
"enum": [
"public",
@@ -26284,6 +26314,7 @@
"x-go-name": "Description"
},
"email": {
"description": "The email address of the user",
"type": "string",
"format": "email",
"x-go-name": "Email"
@@ -26331,12 +26362,13 @@
"x-go-name": "Restricted"
},
"source_id": {
"description": "The authentication source ID to associate with the user",
"type": "integer",
"format": "int64",
"x-go-name": "SourceID"
},
"visibility": {
"description": "User visibility level: public, limited, or private\npublic UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate",
"description": "User visibility level: public, limited, or private",
"type": "string",
"enum": [
"public",
@@ -26359,6 +26391,7 @@
"type": "object",
"properties": {
"email": {
"description": "The email address",
"type": "string",
"format": "email",
"x-go-name": "Email"
@@ -26437,6 +26470,7 @@
"$ref": "#/definitions/CommitUser"
},
"created": {
"description": "Created is the time when the commit was created",
"type": "string",
"format": "date-time",
"x-go-name": "Created"
@@ -26576,6 +26610,7 @@
"x-go-name": "CanSign"
},
"created_at": {
"description": "The date and time when the GPG key was created",
"type": "string",
"format": "date-time",
"x-go-name": "Created"
@@ -26589,6 +26624,7 @@
"x-go-name": "Emails"
},
"expires_at": {
"description": "The date and time when the GPG key expires",
"type": "string",
"format": "date-time",
"x-go-name": "Expires"
@@ -27077,6 +27113,7 @@
"x-go-name": "Config"
},
"created_at": {
"description": "The date and time when the webhook was created",
"type": "string",
"format": "date-time",
"x-go-name": "Created"
@@ -27106,6 +27143,7 @@
"x-go-name": "Type"
},
"updated_at": {
"description": "The date and time when the webhook was last updated",
"type": "string",
"format": "date-time",
"x-go-name": "Updated"
@@ -27118,6 +27156,7 @@
"type": "object",
"properties": {
"email": {
"description": "Email is the person's email address",
"type": "string",
"format": "email",
"x-go-name": "Email"
@@ -27652,8 +27691,9 @@
"type": "string"
},
"Wiki": {
"description": "Is it a wiki page? (use mode=wiki instead)\n\nDeprecated: true",
"type": "boolean"
"description": "Is it a wiki page? (use mode=wiki instead)",
"type": "boolean",
"x-deprecated": true
}
},
"x-go-package": "gitea.dev/modules/structs"
@@ -27679,8 +27719,9 @@
"type": "string"
},
"Wiki": {
"description": "Is it a wiki page? (use mode=wiki instead)\n\nDeprecated: true",
"type": "boolean"
"description": "Is it a wiki page? (use mode=wiki instead)",
"type": "boolean",
"x-deprecated": true
}
},
"x-go-package": "gitea.dev/modules/structs"
@@ -27916,7 +27957,7 @@
"x-go-name": "OpenIssues"
},
"state": {
"description": "State indicates if the milestone is open or closed\nopen StateOpen pr is opened\nclosed StateClosed pr is closed",
"description": "State indicates if the milestone is open or closed",
"type": "string",
"enum": [
"open",
@@ -27953,142 +27994,6 @@
},
"x-go-package": "gitea.dev/modules/structs"
},
"NodeInfo": {
"description": "NodeInfo contains standardized way of exposing metadata about a server running one of the distributed social networks",
"type": "object",
"properties": {
"metadata": {
"description": "Metadata contains free form key value pairs for software specific values",
"type": "object",
"x-go-name": "Metadata"
},
"openRegistrations": {
"description": "OpenRegistrations indicates if new user registrations are accepted",
"type": "boolean",
"x-go-name": "OpenRegistrations"
},
"protocols": {
"description": "Protocols lists the protocols supported by this server",
"type": "array",
"items": {
"type": "string"
},
"x-go-name": "Protocols"
},
"services": {
"$ref": "#/definitions/NodeInfoServices"
},
"software": {
"$ref": "#/definitions/NodeInfoSoftware"
},
"usage": {
"$ref": "#/definitions/NodeInfoUsage"
},
"version": {
"description": "Version specifies the schema version",
"type": "string",
"x-go-name": "Version"
}
},
"x-go-package": "gitea.dev/modules/structs"
},
"NodeInfoServices": {
"description": "NodeInfoServices contains the third party sites this server can connect to via their application API",
"type": "object",
"properties": {
"inbound": {
"description": "Inbound lists services that can deliver content to this server",
"type": "array",
"items": {
"type": "string"
},
"x-go-name": "Inbound"
},
"outbound": {
"description": "Outbound lists services this server can deliver content to",
"type": "array",
"items": {
"type": "string"
},
"x-go-name": "Outbound"
}
},
"x-go-package": "gitea.dev/modules/structs"
},
"NodeInfoSoftware": {
"description": "NodeInfoSoftware contains Metadata about server software in use",
"type": "object",
"properties": {
"homepage": {
"description": "Homepage is the URL to the homepage of this server software",
"type": "string",
"x-go-name": "Homepage"
},
"name": {
"description": "Name is the canonical name of this server software",
"type": "string",
"x-go-name": "Name"
},
"repository": {
"description": "Repository is the URL to the source code repository",
"type": "string",
"x-go-name": "Repository"
},
"version": {
"description": "Version is the version of this server software",
"type": "string",
"x-go-name": "Version"
}
},
"x-go-package": "gitea.dev/modules/structs"
},
"NodeInfoUsage": {
"description": "NodeInfoUsage contains usage statistics for this server",
"type": "object",
"properties": {
"localComments": {
"description": "LocalComments is the total amount of comments made by users local to this server",
"type": "integer",
"format": "int64",
"x-go-name": "LocalComments"
},
"localPosts": {
"description": "LocalPosts is the total amount of posts made by users local to this server",
"type": "integer",
"format": "int64",
"x-go-name": "LocalPosts"
},
"users": {
"$ref": "#/definitions/NodeInfoUsageUsers"
}
},
"x-go-package": "gitea.dev/modules/structs"
},
"NodeInfoUsageUsers": {
"description": "NodeInfoUsageUsers contains statistics about the users of this server",
"type": "object",
"properties": {
"activeHalfyear": {
"description": "ActiveHalfyear is the amount of users that signed in at least once in the last 180 days",
"type": "integer",
"format": "int64",
"x-go-name": "ActiveHalfyear"
},
"activeMonth": {
"description": "ActiveMonth is the amount of users that signed in at least once in the last 30 days",
"type": "integer",
"format": "int64",
"x-go-name": "ActiveMonth"
},
"total": {
"description": "Total is the total amount of users on this server",
"type": "integer",
"format": "int64",
"x-go-name": "Total"
}
},
"x-go-package": "gitea.dev/modules/structs"
},
"Note": {
"description": "Note contains information related to a git note",
"type": "object",
@@ -28137,7 +28042,7 @@
"x-go-name": "LatestCommentURL"
},
"state": {
"description": "State indicates the current state of the notification subject\nopen NotifySubjectStateOpen is an open subject\nclosed NotifySubjectStateClosed is a closed subject\nmerged NotifySubjectStateMerged is a merged pull request",
"description": "State indicates the current state of the notification subject",
"type": "string",
"enum": [
"open",
@@ -28153,7 +28058,7 @@
"x-go-name": "Title"
},
"type": {
"description": "Type indicates the type of the notification subject\nIssue NotifySubjectIssue a issue is subject of an notification\nPull NotifySubjectPull a pull is subject of an notification\nCommit NotifySubjectCommit a commit is subject of an notification\nRepository NotifySubjectRepository a repository is subject of an notification",
"description": "Type indicates the type of the notification subject",
"type": "string",
"enum": [
"Issue",
@@ -28315,7 +28220,7 @@
"x-go-name": "UserName"
},
"visibility": {
"description": "The visibility level of the organization (public, limited, private)\npublic UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate",
"description": "The visibility level of the organization (public, limited, private)",
"type": "string",
"enum": [
"public",
@@ -28401,6 +28306,7 @@
"type": "object",
"properties": {
"created_at": {
"description": "The date and time when the package was created",
"type": "string",
"format": "date-time",
"x-go-name": "CreatedAt"
@@ -28532,6 +28438,7 @@
"x-go-name": "Removed"
},
"timestamp": {
"description": "The timestamp when the commit was made",
"type": "string",
"format": "date-time",
"x-go-name": "Timestamp"
@@ -28684,6 +28591,7 @@
"type": "object",
"properties": {
"created_at": {
"description": "Created is the time when the key was added",
"type": "string",
"format": "date-time",
"x-go-name": "Created"
@@ -28917,7 +28825,7 @@
"x-go-name": "ReviewComments"
},
"state": {
"description": "The current state of the pull request\nopen StateOpen pr is opened\nclosed StateClosed pr is closed",
"description": "The current state of the pull request",
"type": "string",
"enum": [
"open",
@@ -29260,6 +29168,7 @@
"x-go-name": "Reaction"
},
"created_at": {
"description": "The date and time when the reaction was created",
"type": "string",
"format": "date-time",
"x-go-name": "Created"
@@ -29432,7 +29341,7 @@
"type": "object",
"properties": {
"permission": {
"description": "Permission level of the collaborator\nnone AccessLevelNameNone\nread AccessLevelNameRead\nwrite AccessLevelNameWrite\nadmin AccessLevelNameAdmin\nowner AccessLevelNameOwner",
"description": "Permission level of the collaborator",
"type": "string",
"enum": [
"none",
@@ -29731,7 +29640,7 @@
"x-go-name": "Name"
},
"object_format_name": {
"description": "ObjectFormatName of the underlying git repository\nsha1 ObjectFormatSHA1\nsha256 ObjectFormatSHA256",
"description": "ObjectFormatName of the underlying git repository",
"type": "string",
"enum": [
"sha1",
@@ -29928,6 +29837,7 @@
"type": "object",
"properties": {
"created": {
"description": "Created is the time when the stopwatch was started",
"type": "string",
"format": "date-time",
"x-go-name": "Created"
@@ -30030,6 +29940,7 @@
"type": "object",
"properties": {
"created_at": {
"description": "The date and time when the tag protection was created",
"type": "string",
"format": "date-time",
"x-go-name": "Created"
@@ -30046,6 +29957,7 @@
"x-go-name": "NamePattern"
},
"updated_at": {
"description": "The date and time when the tag protection was last updated",
"type": "string",
"format": "date-time",
"x-go-name": "Updated"
@@ -30115,10 +30027,12 @@
"x-go-name": "Permission"
},
"units": {
"description": "Deprecated: This variable should be replaced by UnitsMap and will be dropped in later versions.",
"type": "array",
"items": {
"type": "string"
},
"x-deprecated": true,
"x-go-name": "Units",
"example": [
"repo.code",
@@ -30149,7 +30063,7 @@
}
},
"visibility": {
"description": "Team visibility within the organization. \"private\" teams are only\nlistable by members and org owners; \"limited\" teams are listable by\nany organization member; \"public\" teams are listable by any signed-in\nuser.\npublic TeamVisibilityPublic\nlimited TeamVisibilityLimited\nprivate TeamVisibilityPrivate",
"description": "Team visibility within the organization. \"private\" teams are only\nlistable by members and org owners; \"limited\" teams are listable by\nany organization member; \"public\" teams are listable by any signed-in\nuser.",
"type": "string",
"enum": [
"public",
@@ -30669,7 +30583,7 @@
"x-go-name": "StarredRepos"
},
"visibility": {
"description": "User visibility level option: public, limited, private\npublic UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate",
"description": "User visibility level option: public, limited, private",
"type": "string",
"enum": [
"public",
@@ -31501,12 +31415,6 @@
"type": "string"
}
},
"MergeUpstreamRequest": {
"description": "",
"schema": {
"$ref": "#/definitions/MergeUpstreamRequest"
}
},
"MergeUpstreamResponse": {
"description": "",
"schema": {
@@ -31528,12 +31436,6 @@
}
}
},
"NodeInfo": {
"description": "NodeInfo",
"schema": {
"$ref": "#/definitions/NodeInfo"
}
},
"Note": {
"description": "Note",
"schema": {
@@ -31711,12 +31613,6 @@
}
}
},
"Reference": {
"description": "Reference",
"schema": {
"$ref": "#/definitions/Reference"
}
},
"ReferenceList": {
"description": "ReferenceList",
"schema": {
@@ -31812,12 +31708,6 @@
"$ref": "#/definitions/SearchResults"
}
},
"Secret": {
"description": "Secret",
"schema": {
"$ref": "#/definitions/Secret"
}
},
"SecretList": {
"description": "SecretList",
"schema": {
@@ -31833,12 +31723,6 @@
"$ref": "#/definitions/ServerVersion"
}
},
"StopWatch": {
"description": "StopWatch",
"schema": {
"$ref": "#/definitions/StopWatch"
}
},
"StopWatchList": {
"description": "StopWatchList",
"schema": {
@@ -32085,15 +31969,6 @@
"notFound": {
"description": "APINotFound is a not found empty response"
},
"parameterBodies": {
"description": "parameterBodies",
"schema": {
"$ref": "#/definitions/LockIssueOption"
}
},
"redirect": {
"description": "APIRedirect is a redirect response"
},
"repoArchivedError": {
"description": "APIRepoArchivedError is an error that is raised when an archived repo should be modified",
"headers": {
+88 -235
View File
@@ -802,16 +802,6 @@
},
"description": "MarkupRender is a rendered markup document"
},
"MergeUpstreamRequest": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MergeUpstreamRequest"
}
}
},
"description": ""
},
"MergeUpstreamResponse": {
"content": {
"application/json": {
@@ -845,16 +835,6 @@
},
"description": "MilestoneList"
},
"NodeInfo": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NodeInfo"
}
}
},
"description": "NodeInfo"
},
"Note": {
"content": {
"application/json": {
@@ -1128,16 +1108,6 @@
},
"description": "ReactionList"
},
"Reference": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Reference"
}
}
},
"description": "Reference"
},
"ReferenceList": {
"content": {
"application/json": {
@@ -1287,16 +1257,6 @@
},
"description": "SearchResults"
},
"Secret": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Secret"
}
}
},
"description": "Secret"
},
"SecretList": {
"content": {
"application/json": {
@@ -1320,16 +1280,6 @@
},
"description": "ServerVersion"
},
"StopWatch": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StopWatch"
}
}
},
"description": "StopWatch"
},
"StopWatchList": {
"content": {
"application/json": {
@@ -1696,19 +1646,6 @@
"notFound": {
"description": "APINotFound is a not found empty response"
},
"parameterBodies": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LockIssueOption"
}
}
},
"description": "parameterBodies"
},
"redirect": {
"description": "APIRedirect is a redirect response"
},
"repoArchivedError": {
"description": "APIRepoArchivedError is an error that is raised when an archived repo should be modified",
"headers": {
@@ -2563,7 +2500,7 @@
"$ref": "#/components/schemas/RepoWritePermission"
}
],
"description": "Permission level to grant the collaborator\nread RepoWritePermissionRead\nwrite RepoWritePermissionWrite\nadmin RepoWritePermissionAdmin"
"description": "Permission level to grant the collaborator"
}
},
"type": "object",
@@ -2713,6 +2650,7 @@
"x-go-name": "DownloadURL"
},
"created_at": {
"description": "Created is the time when the attachment was uploaded",
"format": "date-time",
"type": "string",
"x-go-name": "Created"
@@ -2862,9 +2800,8 @@
"x-go-name": "BlockOnRejectedReviews"
},
"branch_name": {
"deprecated": true,
"description": "Deprecated: true",
"type": "string",
"x-deprecated": true,
"x-go-name": "BranchName"
},
"bypass_allowlist_teams": {
@@ -3196,7 +3133,7 @@
"$ref": "#/components/schemas/CommitStatusState"
}
],
"description": "State is the overall combined status state\npending CommitStatusPending is for when the CommitStatus is Pending\nsuccess CommitStatusSuccess is for when the CommitStatus is Success\nerror CommitStatusError is for when the CommitStatus is Error\nfailure CommitStatusFailure is for when the CommitStatus is Failure\nwarning CommitStatusWarning is for when the CommitStatus is Warning\nskipped CommitStatusSkipped is for when CommitStatus is Skipped"
"description": "State is the overall combined status state"
},
"statuses": {
"description": "Statuses contains all individual commit statuses",
@@ -3302,6 +3239,7 @@
"$ref": "#/components/schemas/User"
},
"created": {
"description": "Created is the time when the commit was created",
"format": "date-time",
"type": "string",
"x-go-name": "Created"
@@ -3368,11 +3306,13 @@
"description": "CommitDateOptions store dates for GIT_AUTHOR_DATE and GIT_COMMITTER_DATE",
"properties": {
"author": {
"description": "Author is the author date for the commit",
"format": "date-time",
"type": "string",
"x-go-name": "Author"
},
"committer": {
"description": "Committer is the committer date for the commit",
"format": "date-time",
"type": "string",
"x-go-name": "Committer"
@@ -3384,6 +3324,7 @@
"CommitMeta": {
"properties": {
"created": {
"description": "Created is the time when the commit was created",
"format": "date-time",
"type": "string",
"x-go-name": "Created"
@@ -3462,7 +3403,7 @@
"$ref": "#/components/schemas/CommitStatusState"
}
],
"description": "State represents the status state (pending, success, error, failure)\npending CommitStatusPending is for when the CommitStatus is Pending\nsuccess CommitStatusSuccess is for when the CommitStatus is Success\nerror CommitStatusError is for when the CommitStatus is Error\nfailure CommitStatusFailure is for when the CommitStatus is Failure\nwarning CommitStatusWarning is for when the CommitStatus is Warning\nskipped CommitStatusSkipped is for when CommitStatus is Skipped"
"description": "State represents the status state (pending, success, error, failure)"
},
"target_url": {
"description": "TargetURL is the URL to link to for more details",
@@ -3504,6 +3445,7 @@
"x-go-name": "Date"
},
"email": {
"description": "Email is the person's email address",
"format": "email",
"type": "string",
"x-go-name": "Email"
@@ -3754,9 +3696,8 @@
"x-go-name": "BlockOnRejectedReviews"
},
"branch_name": {
"deprecated": true,
"description": "Deprecated: true",
"type": "string",
"x-deprecated": true,
"x-go-name": "BranchName"
},
"bypass_allowlist_teams": {
@@ -3910,10 +3851,10 @@
"x-go-name": "BranchName"
},
"old_branch_name": {
"deprecated": true,
"description": "Deprecated: true\nName of the old branch to create from",
"description": "Name of the old branch to create from",
"type": "string",
"uniqueItems": true,
"x-deprecated": true,
"x-go-name": "OldBranchName"
},
"old_ref_name": {
@@ -4036,6 +3977,7 @@
"properties": {
"active": {
"default": false,
"description": "Whether the webhook should be active upon creation",
"type": "boolean",
"x-go-name": "Active"
},
@@ -4066,6 +4008,7 @@
"x-go-name": "Name"
},
"type": {
"description": "The type of the webhook to create",
"enum": [
"dingtalk",
"discord",
@@ -4101,6 +4044,7 @@
"description": "CreateIssueCommentOption options for creating a comment on an issue",
"properties": {
"body": {
"description": "Body is the comment text content",
"type": "string",
"x-go-name": "Body"
}
@@ -4231,6 +4175,7 @@
"x-go-name": "IsArchived"
},
"name": {
"description": "Name is the display name for the new label",
"type": "string",
"x-go-name": "Name"
}
@@ -4251,12 +4196,18 @@
"x-go-name": "Description"
},
"due_on": {
"description": "Deadline is the due date for the milestone",
"format": "date-time",
"type": "string",
"x-go-name": "Deadline"
},
"state": {
"$ref": "#/components/schemas/StateType"
"allOf": [
{
"$ref": "#/components/schemas/StateType"
}
],
"description": "State indicates the initial state of the milestone"
},
"title": {
"description": "Title is the title of the new milestone",
@@ -4356,7 +4307,7 @@
"$ref": "#/components/schemas/UserVisibility"
}
],
"description": "possible values are `public` (default), `limited` or `private`\npublic UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate"
"description": "possible values are `public` (default), `limited` or `private`"
},
"website": {
"description": "The website URL of the organization",
@@ -4636,7 +4587,7 @@
"$ref": "#/components/schemas/ObjectFormatName"
}
],
"description": "ObjectFormatName of the underlying git repository, empty string for default (sha1)\nsha1 ObjectFormatSHA1\nsha256 ObjectFormatSHA256"
"description": "ObjectFormatName of the underlying git repository, empty string for default (sha1)"
},
"private": {
"description": "Whether the repository is private",
@@ -4690,7 +4641,7 @@
"$ref": "#/components/schemas/CommitStatusState"
}
],
"description": "State represents the status state to set (pending, success, error, failure)\npending CommitStatusPending is for when the CommitStatus is Pending\nsuccess CommitStatusSuccess is for when the CommitStatus is Success\nerror CommitStatusError is for when the CommitStatus is Error\nfailure CommitStatusFailure is for when the CommitStatus is Failure\nwarning CommitStatusWarning is for when the CommitStatus is Warning\nskipped CommitStatusSkipped is for when CommitStatus is Skipped"
"description": "State represents the status state to set (pending, success, error, failure)"
},
"target_url": {
"description": "TargetURL is the URL to link to for more details",
@@ -4711,6 +4662,7 @@
"x-go-name": "Message"
},
"tag_name": {
"description": "The name of the tag to create",
"type": "string",
"x-go-name": "TagName"
},
@@ -4780,13 +4732,15 @@
"$ref": "#/components/schemas/RepoWritePermission"
},
"units": {
"deprecated": true,
"description": "Deprecated: This variable should be replaced by UnitsMap and will be dropped in later versions.",
"example": [
"repo.actions",
"repo.packages",
"repo.code",
"repo.issues",
"repo.ext_issues",
"repo.wiki",
"repo.ext_wiki",
"repo.pulls",
"repo.releases",
"repo.projects",
@@ -4796,13 +4750,25 @@
"type": "string"
},
"type": "array",
"x-deprecated": true,
"x-go-name": "Units"
},
"units_map": {
"additionalProperties": {
"type": "string"
},
"example": "{\"repo.actions\",\"repo.packages\",\"repo.code\":\"read\",\"repo.issues\":\"write\",\"repo.ext_issues\":\"none\",\"repo.wiki\":\"admin\",\"repo.pulls\":\"owner\",\"repo.releases\":\"none\",\"repo.projects\":\"none\",\"repo.ext_wiki\":\"none\"}",
"example": {
"repo.actions": "read",
"repo.code": "read",
"repo.ext_issues": "none",
"repo.ext_wiki": "none",
"repo.issues": "write",
"repo.packages": "read",
"repo.projects": "none",
"repo.pulls": "owner",
"repo.releases": "none",
"repo.wiki": "admin"
},
"type": "object",
"x-go-name": "UnitsMap"
},
@@ -4812,7 +4778,7 @@
"$ref": "#/components/schemas/TeamVisibility"
}
],
"description": "Team visibility within the organization. Defaults to \"private\".\npublic TeamVisibilityPublic\nlimited TeamVisibilityLimited\nprivate TeamVisibilityPrivate"
"description": "Team visibility within the organization. Defaults to \"private\"."
}
},
"required": [
@@ -4831,7 +4797,6 @@
"x-go-name": "Created"
},
"email": {
"format": "email",
"type": "string",
"x-go-name": "Email"
},
@@ -4883,7 +4848,7 @@
"$ref": "#/components/schemas/UserVisibility"
}
],
"description": "User visibility level: public, limited, or private\npublic UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate"
"description": "User visibility level: public, limited, or private"
}
},
"required": [
@@ -5079,6 +5044,7 @@
"description": "DeployKey a deploy key",
"properties": {
"created_at": {
"description": "Created is the time when the deploy key was added",
"format": "date-time",
"type": "string",
"x-go-name": "Created"
@@ -5413,6 +5379,7 @@
"description": "EditIssueCommentOption options for editing a comment",
"properties": {
"body": {
"description": "Body is the updated comment text content",
"type": "string",
"x-go-name": "Body"
}
@@ -5585,7 +5552,7 @@
"$ref": "#/components/schemas/UserVisibility"
}
],
"description": "possible values are `public`, `limited` or `private`\npublic UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate"
"description": "possible values are `public`, `limited` or `private`"
},
"website": {
"description": "The website URL of the organization",
@@ -5967,6 +5934,8 @@
"$ref": "#/components/schemas/RepoWritePermission"
},
"units": {
"deprecated": true,
"description": "Deprecated: This variable should be replaced by UnitsMap and will be dropped in later versions.",
"example": [
"repo.code",
"repo.issues",
@@ -5981,6 +5950,7 @@
"type": "string"
},
"type": "array",
"x-deprecated": true,
"x-go-name": "Units"
},
"units_map": {
@@ -6006,7 +5976,7 @@
"$ref": "#/components/schemas/TeamVisibility"
}
],
"description": "Team visibility within the organization. When omitted, visibility is\nleft unchanged.\npublic TeamVisibilityPublic\nlimited TeamVisibilityLimited\nprivate TeamVisibilityPrivate"
"description": "Team visibility within the organization. When omitted, visibility is\nleft unchanged."
}
},
"required": [
@@ -6049,6 +6019,7 @@
"x-go-name": "Description"
},
"email": {
"description": "The email address of the user",
"format": "email",
"type": "string",
"x-go-name": "Email"
@@ -6096,6 +6067,7 @@
"x-go-name": "Restricted"
},
"source_id": {
"description": "The authentication source ID to associate with the user",
"format": "int64",
"type": "integer",
"x-go-name": "SourceID"
@@ -6106,7 +6078,7 @@
"$ref": "#/components/schemas/UserVisibility"
}
],
"description": "User visibility level: public, limited, or private\npublic UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate"
"description": "User visibility level: public, limited, or private"
},
"website": {
"description": "The user's personal website URL",
@@ -6125,6 +6097,7 @@
"description": "Email an email address belonging to a user",
"properties": {
"email": {
"description": "The email address",
"format": "email",
"type": "string",
"x-go-name": "Email"
@@ -6204,6 +6177,7 @@
"$ref": "#/components/schemas/CommitUser"
},
"created": {
"description": "Created is the time when the commit was created",
"format": "date-time",
"type": "string",
"x-go-name": "Created"
@@ -6346,6 +6320,7 @@
"x-go-name": "CanSign"
},
"created_at": {
"description": "The date and time when the GPG key was created",
"format": "date-time",
"type": "string",
"x-go-name": "Created"
@@ -6359,6 +6334,7 @@
"x-go-name": "Emails"
},
"expires_at": {
"description": "The date and time when the GPG key expires",
"format": "date-time",
"type": "string",
"x-go-name": "Expires"
@@ -6851,6 +6827,7 @@
"x-go-name": "Config"
},
"created_at": {
"description": "The date and time when the webhook was created",
"format": "date-time",
"type": "string",
"x-go-name": "Created"
@@ -6880,6 +6857,7 @@
"x-go-name": "Type"
},
"updated_at": {
"description": "The date and time when the webhook was last updated",
"format": "date-time",
"type": "string",
"x-go-name": "Updated"
@@ -6892,6 +6870,7 @@
"description": "Identity for a person's identity like an author or committer",
"properties": {
"email": {
"description": "Email is the person's email address",
"format": "email",
"type": "string",
"x-go-name": "Email"
@@ -7426,9 +7405,9 @@
"type": "string"
},
"Wiki": {
"deprecated": true,
"description": "Is it a wiki page? (use mode=wiki instead)\n\nDeprecated: true",
"type": "boolean"
"description": "Is it a wiki page? (use mode=wiki instead)",
"type": "boolean",
"x-deprecated": true
}
},
"type": "object",
@@ -7454,9 +7433,9 @@
"type": "string"
},
"Wiki": {
"deprecated": true,
"description": "Is it a wiki page? (use mode=wiki instead)\n\nDeprecated: true",
"type": "boolean"
"description": "Is it a wiki page? (use mode=wiki instead)",
"type": "boolean",
"x-deprecated": true
}
},
"type": "object",
@@ -7698,7 +7677,7 @@
"$ref": "#/components/schemas/StateType"
}
],
"description": "State indicates if the milestone is open or closed\nopen StateOpen pr is opened\nclosed StateClosed pr is closed"
"description": "State indicates if the milestone is open or closed"
},
"title": {
"description": "Title is the title of the milestone",
@@ -7729,142 +7708,6 @@
"type": "object",
"x-go-package": "gitea.dev/modules/structs"
},
"NodeInfo": {
"description": "NodeInfo contains standardized way of exposing metadata about a server running one of the distributed social networks",
"properties": {
"metadata": {
"description": "Metadata contains free form key value pairs for software specific values",
"type": "object",
"x-go-name": "Metadata"
},
"openRegistrations": {
"description": "OpenRegistrations indicates if new user registrations are accepted",
"type": "boolean",
"x-go-name": "OpenRegistrations"
},
"protocols": {
"description": "Protocols lists the protocols supported by this server",
"items": {
"type": "string"
},
"type": "array",
"x-go-name": "Protocols"
},
"services": {
"$ref": "#/components/schemas/NodeInfoServices"
},
"software": {
"$ref": "#/components/schemas/NodeInfoSoftware"
},
"usage": {
"$ref": "#/components/schemas/NodeInfoUsage"
},
"version": {
"description": "Version specifies the schema version",
"type": "string",
"x-go-name": "Version"
}
},
"type": "object",
"x-go-package": "gitea.dev/modules/structs"
},
"NodeInfoServices": {
"description": "NodeInfoServices contains the third party sites this server can connect to via their application API",
"properties": {
"inbound": {
"description": "Inbound lists services that can deliver content to this server",
"items": {
"type": "string"
},
"type": "array",
"x-go-name": "Inbound"
},
"outbound": {
"description": "Outbound lists services this server can deliver content to",
"items": {
"type": "string"
},
"type": "array",
"x-go-name": "Outbound"
}
},
"type": "object",
"x-go-package": "gitea.dev/modules/structs"
},
"NodeInfoSoftware": {
"description": "NodeInfoSoftware contains Metadata about server software in use",
"properties": {
"homepage": {
"description": "Homepage is the URL to the homepage of this server software",
"type": "string",
"x-go-name": "Homepage"
},
"name": {
"description": "Name is the canonical name of this server software",
"type": "string",
"x-go-name": "Name"
},
"repository": {
"description": "Repository is the URL to the source code repository",
"type": "string",
"x-go-name": "Repository"
},
"version": {
"description": "Version is the version of this server software",
"type": "string",
"x-go-name": "Version"
}
},
"type": "object",
"x-go-package": "gitea.dev/modules/structs"
},
"NodeInfoUsage": {
"description": "NodeInfoUsage contains usage statistics for this server",
"properties": {
"localComments": {
"description": "LocalComments is the total amount of comments made by users local to this server",
"format": "int64",
"type": "integer",
"x-go-name": "LocalComments"
},
"localPosts": {
"description": "LocalPosts is the total amount of posts made by users local to this server",
"format": "int64",
"type": "integer",
"x-go-name": "LocalPosts"
},
"users": {
"$ref": "#/components/schemas/NodeInfoUsageUsers"
}
},
"type": "object",
"x-go-package": "gitea.dev/modules/structs"
},
"NodeInfoUsageUsers": {
"description": "NodeInfoUsageUsers contains statistics about the users of this server",
"properties": {
"activeHalfyear": {
"description": "ActiveHalfyear is the amount of users that signed in at least once in the last 180 days",
"format": "int64",
"type": "integer",
"x-go-name": "ActiveHalfyear"
},
"activeMonth": {
"description": "ActiveMonth is the amount of users that signed in at least once in the last 30 days",
"format": "int64",
"type": "integer",
"x-go-name": "ActiveMonth"
},
"total": {
"description": "Total is the total amount of users on this server",
"format": "int64",
"type": "integer",
"x-go-name": "Total"
}
},
"type": "object",
"x-go-package": "gitea.dev/modules/structs"
},
"Note": {
"description": "Note contains information related to a git note",
"properties": {
@@ -7915,7 +7758,7 @@
"x-go-name": "LatestCommentURL"
},
"state": {
"description": "State indicates the current state of the notification subject\nopen NotifySubjectStateOpen is an open subject\nclosed NotifySubjectStateClosed is a closed subject\nmerged NotifySubjectStateMerged is a merged pull request",
"description": "State indicates the current state of the notification subject",
"enum": [
"open",
"closed",
@@ -7931,7 +7774,7 @@
"x-go-name": "Title"
},
"type": {
"description": "Type indicates the type of the notification subject\nIssue NotifySubjectIssue a issue is subject of an notification\nPull NotifySubjectPull a pull is subject of an notification\nCommit NotifySubjectCommit a commit is subject of an notification\nRepository NotifySubjectRepository a repository is subject of an notification",
"description": "Type indicates the type of the notification subject",
"enum": [
"Issue",
"Pull",
@@ -8109,7 +7952,7 @@
"$ref": "#/components/schemas/UserVisibility"
}
],
"description": "The visibility level of the organization (public, limited, private)\npublic UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate"
"description": "The visibility level of the organization (public, limited, private)"
},
"website": {
"description": "The website URL of the organization",
@@ -8187,6 +8030,7 @@
"description": "Package represents a package",
"properties": {
"created_at": {
"description": "The date and time when the package was created",
"format": "date-time",
"type": "string",
"x-go-name": "CreatedAt"
@@ -8319,6 +8163,7 @@
"x-go-name": "Removed"
},
"timestamp": {
"description": "The timestamp when the commit was made",
"format": "date-time",
"type": "string",
"x-go-name": "Timestamp"
@@ -8472,6 +8317,7 @@
"description": "PublicKey publickey is a user key to push code to repository",
"properties": {
"created_at": {
"description": "Created is the time when the key was added",
"format": "date-time",
"type": "string",
"x-go-name": "Created"
@@ -8714,7 +8560,7 @@
"$ref": "#/components/schemas/StateType"
}
],
"description": "The current state of the pull request\nopen StateOpen pr is opened\nclosed StateClosed pr is closed"
"description": "The current state of the pull request"
},
"title": {
"description": "The title of the pull request",
@@ -9049,6 +8895,7 @@
"x-go-name": "Reaction"
},
"created_at": {
"description": "The date and time when the reaction was created",
"format": "date-time",
"type": "string",
"x-go-name": "Created"
@@ -9232,7 +9079,7 @@
"$ref": "#/components/schemas/AccessLevelName"
}
],
"description": "Permission level of the collaborator\nnone AccessLevelNameNone\nread AccessLevelNameRead\nwrite AccessLevelNameWrite\nadmin AccessLevelNameAdmin\nowner AccessLevelNameOwner"
"description": "Permission level of the collaborator"
},
"role_name": {
"description": "RoleName is the name of the permission role",
@@ -9539,7 +9386,7 @@
"$ref": "#/components/schemas/ObjectFormatName"
}
],
"description": "ObjectFormatName of the underlying git repository\nsha1 ObjectFormatSHA1\nsha256 ObjectFormatSHA256"
"description": "ObjectFormatName of the underlying git repository"
},
"open_issues_count": {
"format": "int64",
@@ -9751,6 +9598,7 @@
"description": "StopWatch represent a running stopwatch",
"properties": {
"created": {
"description": "Created is the time when the stopwatch was started",
"format": "date-time",
"type": "string",
"x-go-name": "Created"
@@ -9846,6 +9694,7 @@
"description": "TagProtection represents a tag protection",
"properties": {
"created_at": {
"description": "The date and time when the tag protection was created",
"format": "date-time",
"type": "string",
"x-go-name": "Created"
@@ -9862,6 +9711,7 @@
"x-go-name": "NamePattern"
},
"updated_at": {
"description": "The date and time when the tag protection was last updated",
"format": "date-time",
"type": "string",
"x-go-name": "Updated"
@@ -9922,6 +9772,8 @@
"$ref": "#/components/schemas/AccessLevelName"
},
"units": {
"deprecated": true,
"description": "Deprecated: This variable should be replaced by UnitsMap and will be dropped in later versions.",
"example": [
"repo.code",
"repo.issues",
@@ -9936,6 +9788,7 @@
"type": "string"
},
"type": "array",
"x-deprecated": true,
"x-go-name": "Units"
},
"units_map": {
@@ -9961,7 +9814,7 @@
"$ref": "#/components/schemas/TeamVisibility"
}
],
"description": "Team visibility within the organization. \"private\" teams are only\nlistable by members and org owners; \"limited\" teams are listable by\nany organization member; \"public\" teams are listable by any signed-in\nuser.\npublic TeamVisibilityPublic\nlimited TeamVisibilityLimited\nprivate TeamVisibilityPrivate"
"description": "Team visibility within the organization. \"private\" teams are only\nlistable by members and org owners; \"limited\" teams are listable by\nany organization member; \"public\" teams are listable by any signed-in\nuser."
}
},
"type": "object",
@@ -10493,7 +10346,7 @@
"$ref": "#/components/schemas/UserVisibility"
}
],
"description": "User visibility level option: public, limited, private\npublic UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate"
"description": "User visibility level option: public, limited, private"
},
"website": {
"description": "the user's website",
@@ -344,6 +344,59 @@ jobs:
})
})
t.Run("Filtered required scoped check passes as skipped and allows merge", func(t *testing.T) {
// A required scoped workflow excluded by a paths filter posts a skipped (success) commit status,
// so the required check is satisfied and the PR can merge.
const scopedFilteredPRWorkflow = `name: Scoped Filtered PR
on:
pull_request:
paths:
- src/**
jobs:
scoped-filtered-job:
runs-on: ubuntu-latest
steps:
- run: echo scoped-filtered
`
source := createTestRepo(t, "sw-filtered-source", false)
createRepoWorkflowFile(t, user2, user2Token, source, ".gitea/scoped_workflows/pr.yaml", scopedFilteredPRWorkflow)
registerUserScopedSource(t, source, "pr.yaml") // required
consumer := createTestRepo(t, "sw-filtered-consumer", false)
// Protect the default branch (its own status check stays off, so only the required scoped check gates the merge).
user2Session.MakeRequest(t, NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/settings/branches/edit", consumer.OwnerName, consumer.Name), map[string]string{
"rule_name": consumer.DefaultBranch,
"enable_push": "true",
"block_admin_merge_override": "true", // otherwise the repo owner bypasses the status check
}), http.StatusSeeOther)
// Open a PR that changes a file NOT matching the workflow's `paths: [src/**]`, so it is filtered out.
prFile := &api.CreateFileOptions{
FileOptions: api.FileOptions{
BranchName: consumer.DefaultBranch, NewBranchName: "filtered-pr", Message: "pr change",
Author: api.Identity{Name: user2.Name, Email: user2.Email},
Committer: api.Identity{Name: user2.Name, Email: user2.Email},
Dates: api.CommitDateOptions{Author: time.Now(), Committer: time.Now()},
},
ContentBase64: base64.StdEncoding.EncodeToString([]byte("pr change")),
}
createWorkflowFile(t, user2Token, consumer.OwnerName, consumer.Name, "docs.txt", prFile)
apiCtx := NewAPITestContext(t, user2.Name, consumer.Name, auth_model.AccessTokenScopeWriteRepository)
pr, err := doAPICreatePullRequest(apiCtx, consumer.OwnerName, consumer.Name, consumer.DefaultBranch, "filtered-pr")(t)
require.NoError(t, err)
// Filtered: no scoped run is created, but a skipped commit status is posted on the PR head.
assert.Equal(t, 0, unittest.GetCount(t, &actions_model.ActionRun{RepoID: consumer.ID, IsScopedRun: true}), "filtered scoped workflow creates no run")
assertSkippedCommitStatusExists(t, consumer.ID, pr.Head.Sha, "pull_request")
// The skipped (success) status satisfies the required scoped check (prefixed with the source repo), so the merge is allowed.
assert.NoError(t, queue.GetManager().FlushAll(t.Context(), 5*time.Second))
mergeReq := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge", consumer.OwnerName, consumer.Name, pr.Index),
&forms.MergePullRequestForm{Do: string(repo_model.MergeStyleMerge), MergeMessageField: "merge"}).AddTokenAuth(user2Token)
user2Session.MakeRequest(t, mergeReq, http.StatusOK)
})
t.Run("Settings page required patterns", func(t *testing.T) {
source := createTestRepo(t, "sw-settings-source", false)
createRepoWorkflowFile(t, user2, user2Token, source, ".gitea/scoped_workflows/push.yaml", scopedPushWorkflow)
+19 -2
View File
@@ -215,8 +215,9 @@ jobs:
err = pull_service.NewPullRequest(t.Context(), prOpts)
assert.NoError(t, err)
// the new pull request cannot trigger actions, so there is still only 1 record
// the new pull request is filtered by paths, so no run is created; a skipped commit status is posted instead
assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: baseRepo.ID}))
assertSkippedCommitStatusExists(t, baseRepo.ID, addFileToForkedResp.Commit.SHA, "pull_request_target")
})
}
@@ -338,6 +339,9 @@ jobs:
})
assert.NoError(t, err)
assert.NotEmpty(t, addFileToBranchResp)
// the push to test-skip-ci is filtered by branches, so no run is created; a skipped commit status is posted instead
assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID}))
assertSkippedCommitStatusExists(t, repo.ID, addFileToBranchResp.Commit.SHA, "push")
resp := testPullCreate(t, session, "user2", "skip-ci", true, "master", "test-skip-ci", "[skip ci] test-skip-ci")
@@ -345,7 +349,7 @@ jobs:
url := test.RedirectURL(resp)
assert.Regexp(t, "^/user2/skip-ci/pulls/[0-9]*$", url)
// the pr title contains a configured skip-ci string, so there is still only 1 record
// the pr title contains a configured skip-ci string, so no run and no skipped status are created
assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID}))
})
}
@@ -1879,3 +1883,16 @@ jobs:
runner.fetchNoTask(t)
})
}
// assertSkippedCommitStatusExists asserts that a filtered-out workflow posted a skipped commit status on sha
func assertSkippedCommitStatusExists(t *testing.T, repoID int64, sha, eventSuffix string) {
t.Helper()
statuses, err := git_model.GetLatestCommitStatus(t.Context(), repoID, sha, db.ListOptionsAll)
require.NoError(t, err)
for _, s := range statuses {
if s.State == commitstatus.CommitStatusSkipped && strings.Contains(s.Context, "("+eventSuffix+")") {
return
}
}
assert.Failf(t, "missing skipped commit status", "no skipped commit status with event %q on %s (found %d statuses)", eventSuffix, sha, len(statuses))
}
@@ -241,3 +241,27 @@ func TestGetFileHistoryNotOnMaster(t *testing.T) {
assert.Equal(t, "1", resp.Header().Get("X-Total"))
}
func TestGetFileHistoryEmptyDateRange(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
// Login as User2.
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
// readme.md exists in repo16 but no commits fall before 1970, so the date
// filter yields an empty range: this must return 200 with an empty list,
// not 404 (regression: a valid path with an empty date range was a 404).
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/commits?path=readme.md&sha=good-sign&until=1970-01-01T00:00:00Z", user.Name).
AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
apiData := DecodeJSON(t, resp, []api.Commit{})
assert.Empty(t, apiData)
assert.Equal(t, "0", resp.Header().Get("X-Total"))
// a path that does not exist must still return 404 even with a date filter
req = NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/commits?path=does-not-exist.md&sha=good-sign&until=1970-01-01T00:00:00Z", user.Name).
AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
}
+71
View File
@@ -22,6 +22,7 @@ import (
"gitea.dev/services/auth/source/oauth2"
"gitea.dev/tests"
"github.com/pquerna/otp/totp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"xorm.io/builder"
@@ -489,3 +490,73 @@ func TestOAuth2GroupClaimsManualLinking(t *testing.T) {
})
}
}
// TestOAuth2AutoLinkWithTwoFactor verifies that automatic account linking completes
// after the user passes local 2FA when an OIDC identity matches an existing account.
func TestOAuth2AutoLinkWithTwoFactor(t *testing.T) {
defer tests.PrepareTestEnv(t)()
defer test.MockVariableValue(&setting.OAuth2Client.EnableAutoRegistration, true)()
defer test.MockVariableValue(&setting.OAuth2Client.AccountLinking, setting.OAuth2AccountLinkingAuto)()
defer test.MockVariableValue(&setting.OAuth2Client.Username, setting.OAuth2UsernameEmail)()
const (
sourceName = "test-oauth-auto-link-2fa"
sub = "oidc-auto-link-2fa-sub"
email = "oidc-auto-link-2fa@example.com"
userName = "oidc-auto-link-2fa"
)
srv := newFakeOIDCServer(t, FakeOIDCConfig{Sub: sub, Email: email, Name: "OIDC Auto Link 2FA"})
addOAuth2Source(t, sourceName, oauth2.Source{
Provider: "openidConnect",
ClientID: "test-client-id",
ClientSecret: "test-client-secret",
OpenIDConnectAutoDiscoveryURL: srv.URL + "/.well-known/openid-configuration",
})
authSource, err := auth_model.GetActiveOAuth2SourceByAuthName(t.Context(), sourceName)
require.NoError(t, err)
localUser := &user_model.User{Name: userName, Email: email}
require.NoError(t, user_model.CreateUser(t.Context(), localUser, &user_model.Meta{}))
otpKey, err := totp.Generate(totp.GenerateOpts{
SecretSize: 40,
Issuer: "gitea-test",
AccountName: localUser.Name,
})
require.NoError(t, err)
tfa := &auth_model.TwoFactor{UID: localUser.ID}
require.NoError(t, tfa.SetSecret(otpKey.Secret()))
require.NoError(t, auth_model.NewTwoFactor(t.Context(), tfa))
unittest.AssertNotExistsBean(t, &user_model.ExternalLoginUser{ExternalID: sub, LoginSourceID: authSource.ID}, unittest.OrderBy("external_id ASC"))
session := emptyTestSession(t)
resp := session.MakeRequest(t, NewRequest(t, "GET", "/user/oauth2/"+sourceName), http.StatusTemporaryRedirect)
location := resp.Header().Get("Location")
u, err := url.Parse(location)
require.NoError(t, err)
state := u.Query().Get("state")
require.NotEmpty(t, state)
callbackURL := fmt.Sprintf("/user/oauth2/%s/callback?code=test-code&state=%s", sourceName, url.QueryEscape(state))
resp = session.MakeRequest(t, NewRequest(t, "GET", callbackURL), http.StatusSeeOther)
assert.Contains(t, resp.Header().Get("Location"), "/user/two_factor")
session.MakeRequest(t, NewRequest(t, "GET", "/user/two_factor"), http.StatusOK)
passcode, err := totp.GenerateCode(otpKey.Secret(), time.Now())
require.NoError(t, err)
req := NewRequestWithValues(t, "POST", "/user/two_factor", map[string]string{
"passcode": passcode,
})
session.MakeRequest(t, req, http.StatusSeeOther)
externalLink := unittest.AssertExistsAndLoadBean(t, &user_model.ExternalLoginUser{ExternalID: sub, LoginSourceID: authSource.ID}, unittest.OrderBy("external_id ASC"))
assert.Equal(t, localUser.ID, externalLink.UserID)
session.MakeRequest(t, NewRequest(t, "GET", "/user/settings"), http.StatusOK)
}
Vendored
-24
View File
@@ -1,9 +1,3 @@
declare module 'eslint-plugin-array-func' {
import type {Eslint} from 'eslint';
const plugin: Eslint.Plugin;
export = plugin;
}
declare module '*.svg' {
const value: string;
export default value;
@@ -47,21 +41,3 @@ declare module '@citation-js/core' {
declare module '@citation-js/plugin-software-formats' {}
declare module '@citation-js/plugin-bibtex' {}
declare module '@citation-js/plugin-csl' {}
declare module 'vue-bar-graph' {
import type {DefineComponent} from 'vue';
interface BarGraphPoint {
value: number;
label: string;
}
export const VueBarGraph: DefineComponent<{
points?: Array<BarGraphPoint>;
barColor?: string;
textColor?: string;
textAltColor?: string;
height?: number;
labelHeight?: number;
}>;
}
+43 -29
View File
@@ -2,7 +2,7 @@
import {computed, nextTick, onBeforeUnmount, onMounted, ref, toRefs, watch} from 'vue';
import {SvgIcon} from '../svg.ts';
import ActionStatusIcon from './ActionStatusIcon.vue';
import {addDelegatedEventListener, createElementFromAttrs, toggleElem} from '../utils/dom.ts';
import {addDelegatedEventListener, createElementFromAttrs} from '../utils/dom.ts';
import {formatDatetime, formatDatetimeISO} from '../utils/time.ts';
import {POST} from '../modules/fetch.ts';
import {copyToClipboardWithFeedback} from '../modules/clipboard.ts';
@@ -247,9 +247,6 @@ function createLogLine(stepIndex: number, startTime: number, line: LogLine, cmd:
`${seconds}s`, // for "Show seconds"
);
toggleElem(logTimeStamp, timeVisible.value['log-time-stamp']);
toggleElem(logTimeSeconds, timeVisible.value['log-time-seconds']);
const lineClass = cmd?.name ? `job-log-line log-line-${cmd.name}` : 'job-log-line';
return createElementFromAttrs('div', {id: `jobstep-${stepIndex}-${line.index}`, class: lineClass},
lineNum, logTimeStamp, logMsg, logTimeSeconds,
@@ -391,9 +388,6 @@ function elStepsContainer(): HTMLElement {
function toggleTimeDisplay(type: 'seconds' | 'stamp') {
timeVisible.value[`log-time-${type}`] = !timeVisible.value[`log-time-${type}`];
for (const el of elStepsContainer().querySelectorAll(`.log-time-${type}`)) {
toggleElem(el, timeVisible.value[`log-time-${type}`]);
}
saveLocaleStorageOptions();
}
@@ -473,7 +467,15 @@ async function hashChangeListener() {
</div>
</div>
<!-- always create the node because we have our own event listeners on it, don't use "v-if" -->
<div class="job-step-container" ref="stepsContainer" v-show="!isCallerJob && currentJob.steps.length">
<div
class="job-step-container"
ref="stepsContainer"
v-show="!isCallerJob && currentJob.steps.length"
:class="{
'log-line-show-timestamps': timeVisible['log-time-stamp'],
'log-line-show-seconds': timeVisible['log-time-seconds']
}"
>
<div class="job-step-section" v-for="(jobStep, stepIdx) in currentJob.steps" :key="stepIdx">
<div
class="job-step-summary"
@@ -681,8 +683,22 @@ async function hashChangeListener() {
scroll-margin-top: 95px;
}
.job-log-line .log-time-stamp,
.job-log-line .log-time-seconds {
display: none;
}
.log-line-show-timestamps .job-log-line .log-time-stamp {
display: inline;
}
.log-line-show-seconds .job-log-line .log-time-seconds {
display: inline;
}
/* class names 'log-time-seconds' and 'log-time-stamp' are used in the method toggleTimeDisplay */
.job-log-line .line-num, .log-time-seconds {
.job-log-line .line-num,
.job-log-line .log-time-seconds {
width: 48px;
color: var(--color-text-light-3);
text-align: right;
@@ -699,16 +715,16 @@ async function hashChangeListener() {
}
.job-log-line .log-time,
.log-time-stamp {
.job-log-line .log-time-stamp {
color: var(--color-text-light-3);
margin-left: 10px;
margin-left: 12px;
white-space: nowrap;
}
.job-step-logs .job-log-line .log-msg {
flex: 1;
white-space: break-spaces;
margin-left: 10px;
margin-left: 12px;
overflow-wrap: anywhere;
}
@@ -775,30 +791,28 @@ async function hashChangeListener() {
border-radius: 0;
}
.job-log-group .job-log-list .job-log-line .log-msg {
margin-left: 2em;
}
.job-log-group-summary {
cursor: pointer;
position: relative;
display: list-item;
list-style: disclosure-closed inside;
padding-left: 58px; /* line-num gutter (48px) + log-msg margin (10px), so the marker sits in the content column */
list-style: none; /* hide the standard disclosure marker (Chrome, Edge, Firefox) */
}
.job-log-group[open] > .job-log-group-summary {
list-style-type: disclosure-open;
.job-log-group-summary::-webkit-details-marker { /* hide the disclosure marker on Safari */
display: none;
}
.job-log-group-summary > .job-log-line {
position: absolute;
inset: 0;
z-index: -1; /* sit behind the disclosure marker */
overflow: hidden;
.log-line-group .log-msg::before {
content: "";
display: inline-block;
vertical-align: middle;
margin-top: -2.5px;
margin-right: 8px;
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
border-left: 6px solid var(--color-text-light-3);
transition: transform 0.1s ease;
}
.job-log-group-summary > .job-log-line .log-msg {
margin-left: 21px;
.job-log-group[open] .log-line-group .log-msg::before {
transform: rotate(90deg);
}
</style>
@@ -1,6 +1,13 @@
<script lang="ts" setup>
import {VueBarGraph} from 'vue-bar-graph';
import {computed, onMounted, shallowRef, useTemplateRef, type ShallowRef} from 'vue';
import {onMounted, shallowRef, useTemplateRef, type ShallowRef} from 'vue';
const barSlotWidth = 40; // horizontal space allotted per author
const chartHeight = 100; // keep in sync with reserved height in template
const innerChartHeight = chartHeight - 28; // 28 = avatar/x-axis label row (20) + 8px padding
const barMidPoint = barSlotWidth / 2;
const barWidth = barSlotWidth - 2; // 2px gap between bars
const avatarSize = 20;
const labelInsideThreshold = 22; // bars at least this tall carry the commit count inside them
const colors = shallowRef({
barColor: 'green',
@@ -18,26 +25,19 @@ type ActivityAuthorData = {
const activityTopAuthors: Array<ActivityAuthorData> = window.config.pageData.repoActivityTopAuthors || [];
const graphPoints = computed(() => {
return activityTopAuthors.map((item) => {
return {
value: item.commits,
label: item.name,
};
});
});
const graphWidth = activityTopAuthors.length * barSlotWidth;
const maxCommits = Math.max(...activityTopAuthors.map((author) => author.commits));
const graphAuthors = computed(() => {
return activityTopAuthors.map((item, idx: number) => {
return {
position: idx + 1,
...item,
};
});
});
const graphWidth = computed(() => {
return activityTopAuthors.length * 40;
const bars = activityTopAuthors.map((author, index) => {
const height = author.commits / maxCommits * innerChartHeight;
return {
author,
index,
x: index * barSlotWidth,
height,
yOffset: innerChartHeight - height,
labelInside: height >= labelInsideThreshold,
};
});
const styleElement = useTemplateRef('styleElement') as Readonly<ShallowRef<HTMLDivElement>>;
@@ -59,49 +59,34 @@ onMounted(() => {
<div>
<div class="activity-bar-graph tw-w-0 tw-h-0" ref="styleElement"/>
<div class="activity-bar-graph-alt tw-w-0 tw-h-0" ref="altStyleElement"/>
<vue-bar-graph
:points="graphPoints"
:show-x-axis="true"
:show-y-axis="false"
:show-values="true"
:width="graphWidth"
:bar-color="colors.barColor"
:text-color="colors.textColor"
:text-alt-color="colors.textAltColor"
:height="100"
:label-height="20"
>
<template #label="opt">
<g v-for="(author, idx) in graphAuthors" :key="author.position">
<a
v-if="opt.bar.index === idx && author.home_link"
:href="author.home_link"
>
<image
:x="`${opt.bar.midPoint - 10}px`"
:y="`${opt.bar.yLabel}px`"
height="20"
width="20"
:href="author.avatar_link"
/>
</a>
<image
v-else-if="opt.bar.index === idx"
:x="`${opt.bar.midPoint - 10}px`"
:y="`${opt.bar.yLabel}px`"
height="20"
width="20"
:href="author.avatar_link"
/>
</g>
</template>
<template #title="opt">
<tspan v-for="(author, idx) in graphAuthors" :key="author.position">
<tspan v-if="opt.bar.index === idx">
{{ author.name }}
</tspan>
</tspan>
</template>
</vue-bar-graph>
<svg :width="graphWidth" :height="chartHeight">
<g v-for="bar in bars" :key="bar.index" :transform="`translate(${bar.x},0)`">
<title>{{ bar.author.name }}</title>
<rect :width="barWidth" :height="bar.height" :x="2" :y="bar.yOffset" :style="{fill: colors.barColor}"/>
<text
:x="barMidPoint"
:y="bar.yOffset"
:dy="bar.labelInside ? '15px' : '-5px'"
text-anchor="middle"
:style="{fill: bar.labelInside ? colors.textAltColor : colors.textColor, font: '10px sans-serif'}"
>{{ bar.author.commits }}</text>
<a v-if="bar.author.home_link" :href="bar.author.home_link">
<image :x="barMidPoint - avatarSize / 2" :y="innerChartHeight + 4" :height="avatarSize" :width="avatarSize" :href="bar.author.avatar_link"/>
</a>
<image v-else :x="barMidPoint - avatarSize / 2" :y="innerChartHeight + 4" :height="avatarSize" :width="avatarSize" :href="bar.author.avatar_link"/>
<line class="axis-line" :x1="barMidPoint" :x2="barMidPoint" :y1="innerChartHeight + 3" :y2="innerChartHeight"/>
</g>
<line class="axis-line" :x1="2" :x2="graphWidth" :y1="innerChartHeight" :y2="innerChartHeight"/>
</svg>
</div>
</template>
<style scoped>
svg {
display: block; /* avoid the inline-baseline gap so the reserved container height matches exactly */
}
.axis-line {
stroke: var(--color-secondary-alpha-60);
stroke-width: 1;
}
</style>
+1 -1
View File
@@ -125,7 +125,7 @@ export async function initDropzone(dropzoneEl: HTMLElement) {
dzInst.removeAllFiles(true);
disableRemovedfileEvent = false;
dropzoneEl.querySelector('.files')!.innerHTML = '';
dropzoneEl.querySelector('.files')!.replaceChildren();
for (const el of dropzoneEl.querySelectorAll('.dz-preview')) el.remove();
fileUuidDict = {};
for (const attachment of respData) {