Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
566eedc
withCredentials support -- initial implementation and tests
sahilm02 Apr 22, 2025
4626f86
Sort the imports on new test
MarkEWaite Apr 25, 2025
a6fd562
Simplify implementation with single binding
MarkEWaite Apr 25, 2025
4bb4317
Update src/test/java/org/jenkinsci/plugin/gitea/credentials/PersonalA…
sahilm02 Apr 25, 2025
33b0b22
Simplify test script
MarkEWaite Apr 25, 2025
38e517e
Merge branch 'feature/withCredentials-support' of github.com:sahilm02…
sahilm02 Apr 25, 2025
c214a56
Add giteaPersonalAccessToken documentation and example
MarkEWaite Apr 25, 2025
9667755
Merge remote-tracking branch 'markwaite/feature/withCredentials-suppo…
sahilm02 Apr 25, 2025
47258b9
Use echo instead of println
MarkEWaite Apr 25, 2025
f9e1723
Improve comment in test
MarkEWaite Apr 25, 2025
c89581d
Merge remote-tracking branch 'markwaite/feature/withCredentials-suppo…
sahilm02 Apr 25, 2025
b4388d9
Use StringCredentials
MarkEWaite Apr 26, 2025
ba4aa66
Use StringCredentials
MarkEWaite Apr 29, 2025
6ae6216
Choose 'Secret text' credential from snippet generator
MarkEWaite Apr 29, 2025
9bd7c77
Merge branch 'jenkinsci:master' into feature/withCredentials-support-…
MarkEWaite May 19, 2025
8401187
Merge branch 'master' into feature/withCredentials-support-using-Stri…
MarkEWaite Nov 26, 2025
c71a294
Include sh and bat in example and test
MarkEWaite Nov 26, 2025
8978f4a
Merge branch 'master' into feature/withCredentials-support
sahilm02 Dec 2, 2025
df93222
Merge remote-tracking branch 'markwaite/feature/withCredentials-suppo…
sahilm02 Dec 2, 2025
80946b7
Merge branch 'feature/withCredentials-support' of github.com:sahilm02…
sahilm02 Dec 2, 2025
b291ead
Update src/test/java/org/jenkinsci/plugin/gitea/credentials/PersonalA…
sahilm02 Dec 9, 2025
748d476
Remove unnecessary files
sahilm02 Dec 9, 2025
86c9133
Merge branch 'feature/withCredentials-support' of github.com:sahilm02…
sahilm02 Dec 9, 2025
8d7beaf
Merge branch 'master' into feature/withCredentials-support
sahilm02 Dec 9, 2025
fc1afca
Fix checkstyle
sahilm02 Dec 12, 2025
8147fe3
Merge branch 'feature/withCredentials-support' of github.com:sahilm02…
sahilm02 Dec 12, 2025
529d3fa
Fix checkstyle
sahilm02 Dec 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 60 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,70 @@

### Configure the item

1. When configuring the new item, select "Repository Sources"
1. When configuring the new item, select "Repository Sources"

ℹ️ **This is only necessary when using `branch-api` plugin version >=2.7.0**

2. In the "Gitea organzations" section, add a new credential of type "Gitea personal access token".
3. Add the access token created before for the jenkins user in Gitea. Ignore the error about the token not having the correct length.
4. In the "Owner" field, add the name of the organization in Gitea you want to build projects for (**not** the full name).
5. Fill the rest of the form as required. Click "Save". The following scan should list the repositories that the jenkins user can see in the organization selected.

## Using a Gitea personal access token in a Jenkins Pipeline

["Using credentials"](https://www.jenkins.io/doc/book/using/using-credentials/) includes a Jenkins Pipeline credentials tutorial.
Additional credentials examples are available in the ["Injecting secrets into builds"](https://docs.cloudbees.com/docs/cloudbees-ci/latest/secure/injecting-secrets) page from CloudBees.

The Gitea plugin includes support for Gitea personal access tokens as Jenkins [credentials](https://www.jenkins.io/doc/book/using/using-credentials/).
Personal access tokens are used to authenticate Gitea repository and API access without using a Gitea username and password.
Gitea personal access tokens are defined in Gitea from the "Applications" page of each Gitea user's "Settings" (/user/settings/applications).
Personal access token permissions can be defined to grant access to a subset of the resources of the Gitea server.

Once a Gitea personal access token has been created in Gitea and added to Jenkins as a credential, it can be referenced from a Pipeline job using the `withCredentials` Pipeline step.
Use the [Pipeline syntax snippet generator](https://www.jenkins.io/pipeline/getting-started-pipelines/#using-snippet-generator) to create an example of the `withCredentials` step.
Choose "Secret text" as the credential type in the snippet generator.

A typical example of a Gitea personal access token in a Jenkins declarative Pipeline would look like:

```groovy
pipeline {
agent any
stages {
stage('Checkout') {
steps {
withCredentials([string(credentialsId: 'my-gitea-token', variable: 'MY_TOKEN')]) {
if (isUnix()) {
sh 'git clone https://[email protected]/exampleUser/private-repo.git'
} else {
bat 'git clone https://%MY_TOKEN%@gitea.com/exampleUser/private-repo.git'
}
}
}
}
}
}
```

A typical example of a Gitea personal access token in a Jenkins scripted Pipeline would look like:

```groovy
node {
stage('Checkout') {
withCredentials([string(credentialsId: 'my-gitea-token', variable: 'MY_TOKEN')]) {
if (isUnix()) {
sh 'git clone https://[email protected]/exampleUser/private-repo.git'
} else {
bat 'git clone https://%MY_TOKEN%@gitea.com/exampleUser/private-repo.git'
}
}
}
}
```

### Note

You should use a single quote (`'`) instead of a double quote (`"`) whenever you can.
This is particularly important in Pipelines where a statement may be interpreted by both the Pipeline engine and an external interpreter, such as a Unix shell (`sh`) or Windows Command (`bat`) or Powershell (`ps`).
This reduces complications with password masking and command processing.
The `sh` step in the above examples properly demonstrates this.
It references an environment variable, so the single-quoted string passes its value unprocessed to the `sh` step, and the shell interprets `$MY_TOKEN`.
9 changes: 9 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>display-url-api</artifactId>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plain-credentials</artifactId>
</dependency>
<!-- Currently just here for interactive testing via hpi:run: -->
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
Expand All @@ -109,6 +113,11 @@
<artifactId>workflow-multibranch</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-basic-steps</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<repositories>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import jenkins.model.Jenkins;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.Symbol;
import org.jenkinsci.plugins.plaincredentials.StringCredentials;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.DataBoundConstructor;
Expand All @@ -45,7 +46,7 @@
* Default implementation of {@link PersonalAccessToken} for use by {@link Jenkins} {@link CredentialsProvider}
* instances that store {@link Secret} locally.
*/
public class PersonalAccessTokenImpl extends BaseStandardCredentials implements StandardUsernameCredentials, PersonalAccessToken {
public class PersonalAccessTokenImpl extends BaseStandardCredentials implements StandardUsernameCredentials, PersonalAccessToken, StringCredentials {
/**
* Our token.
*/
Expand Down Expand Up @@ -94,6 +95,12 @@ public Secret getPassword() {
return getToken();
}

@NonNull
@Override
public Secret getSecret() {
return getToken();
}

/**
* Our descriptor.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.jenkinsci.plugin.gitea.credentials;

import java.nio.charset.StandardCharsets;
import java.util.List;

import org.apache.commons.io.IOUtils;

Check warning on line 6 in src/test/java/org/jenkinsci/plugin/gitea/credentials/PersonalAccessTokenBindingTest.java

View check run for this annotation

ci.jenkins.io / Java Compiler

checkstyle:check

ERROR: (imports) ImportOrder: Extra separation in import group before 'org.apache.commons.io.IOUtils'

Check warning on line 6 in src/test/java/org/jenkinsci/plugin/gitea/credentials/PersonalAccessTokenBindingTest.java

View check run for this annotation

ci.jenkins.io / CheckStyle

ImportOrderCheck

ERROR: Extra separation in import group before 'org.apache.commons.io.IOUtils'
Raw output
<p>Since Checkstyle 3.2</p><p>Checks the ordering/grouping of imports. Features are:</p><ul><li>groups type/static imports: ensures that groups of imports come in a specific order (e.g., java. comes first, javax. comes second, then everything else)</li><li>adds a separation between type import groups : ensures that a blank line sit between each group</li><li>type/static import groups aren't separated internally: ensures that each group aren't separated internally by blank line or comment</li><li>sorts type/static imports inside each group: ensures that imports within each group are in lexicographic order</li><li>sorts according to case: ensures that the comparison between imports is case sensitive, in <a href="https://en.wikipedia.org/wiki/ASCII#Order">ASCII sort order</a></li><li>arrange static imports: ensures the relative order between type imports and static imports (see <a href="property_types.html#importOrder">import orders</a>)</li></ul><p><a href="#ImportOrder_Examples">Examples section</a> contains examples that work with default formatter configurations of Eclipse, IntelliJ IDEA and NetBeans </p>
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;

import com.cloudbees.plugins.credentials.CredentialsProvider;

Check warning on line 14 in src/test/java/org/jenkinsci/plugin/gitea/credentials/PersonalAccessTokenBindingTest.java

View check run for this annotation

ci.jenkins.io / Java Compiler

checkstyle:check

ERROR: (imports) ImportOrder: Extra separation in import group before 'com.cloudbees.plugins.credentials.CredentialsProvider'

Check warning on line 14 in src/test/java/org/jenkinsci/plugin/gitea/credentials/PersonalAccessTokenBindingTest.java

View check run for this annotation

ci.jenkins.io / Java Compiler

checkstyle:check

ERROR: (imports) ImportOrder: Wrong order for 'com.cloudbees.plugins.credentials.CredentialsProvider' import.

Check warning on line 14 in src/test/java/org/jenkinsci/plugin/gitea/credentials/PersonalAccessTokenBindingTest.java

View check run for this annotation

ci.jenkins.io / CheckStyle

ImportOrderCheck

ERROR: Extra separation in import group before 'com.cloudbees.plugins.credentials.CredentialsProvider'
Raw output
<p>Since Checkstyle 3.2</p><p>Checks the ordering/grouping of imports. Features are:</p><ul><li>groups type/static imports: ensures that groups of imports come in a specific order (e.g., java. comes first, javax. comes second, then everything else)</li><li>adds a separation between type import groups : ensures that a blank line sit between each group</li><li>type/static import groups aren't separated internally: ensures that each group aren't separated internally by blank line or comment</li><li>sorts type/static imports inside each group: ensures that imports within each group are in lexicographic order</li><li>sorts according to case: ensures that the comparison between imports is case sensitive, in <a href="https://en.wikipedia.org/wiki/ASCII#Order">ASCII sort order</a></li><li>arrange static imports: ensures the relative order between type imports and static imports (see <a href="property_types.html#importOrder">import orders</a>)</li></ul><p><a href="#ImportOrder_Examples">Examples section</a> contains examples that work with default formatter configurations of Eclipse, IntelliJ IDEA and NetBeans </p>

Check warning on line 14 in src/test/java/org/jenkinsci/plugin/gitea/credentials/PersonalAccessTokenBindingTest.java

View check run for this annotation

ci.jenkins.io / CheckStyle

ImportOrderCheck

ERROR: Wrong order for 'com.cloudbees.plugins.credentials.CredentialsProvider' import.
Raw output
<p>Since Checkstyle 3.2</p><p>Checks the ordering/grouping of imports. Features are:</p><ul><li>groups type/static imports: ensures that groups of imports come in a specific order (e.g., java. comes first, javax. comes second, then everything else)</li><li>adds a separation between type import groups : ensures that a blank line sit between each group</li><li>type/static import groups aren't separated internally: ensures that each group aren't separated internally by blank line or comment</li><li>sorts type/static imports inside each group: ensures that imports within each group are in lexicographic order</li><li>sorts according to case: ensures that the comparison between imports is case sensitive, in <a href="https://en.wikipedia.org/wiki/ASCII#Order">ASCII sort order</a></li><li>arrange static imports: ensures the relative order between type imports and static imports (see <a href="property_types.html#importOrder">import orders</a>)</li></ul><p><a href="#ImportOrder_Examples">Examples section</a> contains examples that work with default formatter configurations of Eclipse, IntelliJ IDEA and NetBeans </p>
import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.CredentialsStore;
import com.cloudbees.plugins.credentials.SystemCredentialsProvider;
import com.cloudbees.plugins.credentials.domains.Domain;

import hudson.model.Run;

Check warning on line 20 in src/test/java/org/jenkinsci/plugin/gitea/credentials/PersonalAccessTokenBindingTest.java

View check run for this annotation

ci.jenkins.io / Java Compiler

checkstyle:check

ERROR: (imports) ImportOrder: Extra separation in import group before 'hudson.model.Run'

Check warning on line 20 in src/test/java/org/jenkinsci/plugin/gitea/credentials/PersonalAccessTokenBindingTest.java

View check run for this annotation

ci.jenkins.io / CheckStyle

ImportOrderCheck

ERROR: Extra separation in import group before 'hudson.model.Run'
Raw output
<p>Since Checkstyle 3.2</p><p>Checks the ordering/grouping of imports. Features are:</p><ul><li>groups type/static imports: ensures that groups of imports come in a specific order (e.g., java. comes first, javax. comes second, then everything else)</li><li>adds a separation between type import groups : ensures that a blank line sit between each group</li><li>type/static import groups aren't separated internally: ensures that each group aren't separated internally by blank line or comment</li><li>sorts type/static imports inside each group: ensures that imports within each group are in lexicographic order</li><li>sorts according to case: ensures that the comparison between imports is case sensitive, in <a href="https://en.wikipedia.org/wiki/ASCII#Order">ASCII sort order</a></li><li>arrange static imports: ensures the relative order between type imports and static imports (see <a href="property_types.html#importOrder">import orders</a>)</li></ul><p><a href="#ImportOrder_Examples">Examples section</a> contains examples that work with default formatter configurations of Eclipse, IntelliJ IDEA and NetBeans </p>

@WithJenkins
class PersonalAccessTokenBindingTest {

private static final String API_TOKEN = "secret";
private static final String API_TOKEN_ID = "personalAccessTokenId";

private JenkinsRule jenkins;

@BeforeEach
void setUp(JenkinsRule rule) throws Exception {
jenkins = rule;
for (CredentialsStore credentialsStore : CredentialsProvider.lookupStores(jenkins.jenkins)) {
if (credentialsStore instanceof SystemCredentialsProvider.StoreImpl) {
List<Domain> domains = credentialsStore.getDomains();
credentialsStore.addCredentials(
domains.get(0),
new PersonalAccessTokenImpl(
CredentialsScope.GLOBAL,
API_TOKEN_ID,
"Gitea Personal Access Token",
API_TOKEN));
}
}
}

@Test
void withCredentials_success() throws Exception {
WorkflowJob project = jenkins.createProject(WorkflowJob.class);
String pipelineText = IOUtils.toString(
getClass().getResourceAsStream("pipeline/withCredentials-pipeline.groovy"), StandardCharsets.UTF_8);
project.setDefinition(new CpsFlowDefinition(pipelineText, false));
Run<?, ?> build = jenkins.buildAndAssertSuccess(project);
// Pipeline script outputs a substring of credential so that it will not be masked
jenkins.assertLogContains("Token1 is ecret", build);
// Pipeline script shell and bat masks credential
jenkins.assertLogContains("API_TOKEN1 is ****", build);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
node {
withCredentials([string(
credentialsId: 'personalAccessTokenId',
variable: 'API_TOKEN1'
)]) {
echo "Token1 is ${API_TOKEN1.substring(1)}"
if (isUnix()) {
sh 'echo API_TOKEN1 is $API_TOKEN1'
} else {
bat 'echo API_TOKEN1 is %API_TOKEN1%'
}
}
}
Loading