Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add gitea release handling #60

Merged
merged 17 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
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
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"cSpell.words": [
"gitea",
"repos"
]
],
"java.configuration.updateBuildConfiguration": "interactive"
}
9 changes: 4 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>scm-api</artifactId>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>branch-api</artifactId>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>git</artifactId>
Expand All @@ -100,11 +104,6 @@
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>branch-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-multibranch</artifactId>
Expand Down
91 changes: 91 additions & 0 deletions src/main/java/org/jenkinsci/plugin/gitea/GiteaReleaseNotifier.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* The MIT License
*
* Copyright (c) 2017-2022, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jenkinsci.plugin.gitea;

import hudson.Extension;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.model.listeners.RunListener;
import java.io.IOException;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.SCMHeadObserver;
import jenkins.scm.api.SCMSource;
import jenkins.util.VirtualFile;
import org.jenkinsci.plugin.gitea.client.api.GiteaConnection;
import org.jenkinsci.plugin.gitea.client.api.GiteaRepository;

public class GiteaReleaseNotifier {

public static void publishArtifacts(Run<?, ?> build, TaskListener listener)
throws IOException, InterruptedException {

if (build.getResult() != Result.SUCCESS) {
// do not push assets when the pipeline wasn't a success
listener.getLogger().format("[Gitea] do not publish assets due to build being non-Successfully%n");
return;
}

final SCMSource s = SCMSource.SourceByItem.findSource(build.getParent());
if (!(s instanceof GiteaSCMSource)) {
listener.getLogger().format("[Gitea] do not publish assets due to source being no GiteaSCMSource%n");
return;
}
final GiteaSCMSource source = (GiteaSCMSource) s;
if (!new GiteaSCMSourceContext(null, SCMHeadObserver.none())
.withTraits(source.getTraits())
.artifactToAssetMappingEnabled()) {
return;
}
final SCMHead head = SCMHead.HeadByItem.findHead(build.getParent());
if (head == null || !(head instanceof ReleaseSCMHead)) {
listener.getLogger().format("[Gitea] do not publish assets due to head either being null or no ReleaseSCMHead%n");
return;
}

try (GiteaConnection c = source.gitea().open()) {
GiteaRepository repository = c.fetchRepository(source.getRepoOwner(), source.getRepository());
long releaseId = ((ReleaseSCMHead) head).getId();

for (Run<?, ?>.Artifact artifact : build.getArtifacts()) {
VirtualFile file = build.getArtifactManager().root().child(artifact.relativePath);
c.createReleaseAttachment(repository, releaseId, artifact.getFileName(), file.open());
listener.getLogger().format("[Gitea] Published asset from archived artifact %s%n", artifact.getFileName());
}
}
}

@Extension
public static class JobCompletedListener extends RunListener<Run<?, ?>> {

@Override
public void onCompleted(Run<?, ?> build, TaskListener listener) {
try {
publishArtifacts(build, listener);
} catch (IOException | InterruptedException e) {
e.printStackTrace(listener.error("Could not upload assets for release"));
}
}
}
}
80 changes: 80 additions & 0 deletions src/main/java/org/jenkinsci/plugin/gitea/GiteaReleaseSCMEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* The MIT License
*
* Copyright (c) 2017-2022, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jenkinsci.plugin.gitea;

import hudson.Extension;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import java.util.logging.Logger;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.SCMHeadEvent;
import jenkins.scm.api.SCMRevision;
import org.jenkinsci.plugin.gitea.client.api.GiteaConnection;
import org.jenkinsci.plugin.gitea.client.api.GiteaReleaseEvent;
import org.jenkinsci.plugin.gitea.client.api.GiteaTag;

public class GiteaReleaseSCMEvent extends AbstractGiteaSCMHeadEvent<GiteaReleaseEvent> {

public static final Logger LOGGER = Logger.getLogger(GiteaReleaseSCMEvent.class.getName());

public GiteaReleaseSCMEvent(GiteaReleaseEvent payload, String origin) {
super(Type.CREATED, payload, origin);
}

@Override
protected Map<SCMHead, SCMRevision> headsFor(GiteaSCMSource source) {
if (getPayload().getRelease().isDraft()) {
// skip draft releases
return Collections.<SCMHead, SCMRevision>emptyMap();
}

String ref = getPayload().getRelease().getTagName();
String sha = null;

try (GiteaConnection c = source.gitea().open()) {
GiteaTag releaseTag = c.fetchTag(source.getRepoOwner(), source.getRepository(), ref);
sha = releaseTag.getCommit().getSha();
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}

ReleaseSCMHead h = new ReleaseSCMHead(ref, getPayload().getRelease().getId());
return Collections.<SCMHead, SCMRevision>singletonMap(h, new ReleaseSCMRevision(h, sha));
}

@Extension
public static class HandlerImpl extends GiteaWebhookHandler<GiteaReleaseSCMEvent, GiteaReleaseEvent> {

@Override
protected GiteaReleaseSCMEvent createEvent(GiteaReleaseEvent payload, String origin) {
return new GiteaReleaseSCMEvent(payload, origin);
}

@Override
protected void process(GiteaReleaseSCMEvent event) {
SCMHeadEvent.fireNow(event);
}
}
}
3 changes: 3 additions & 0 deletions src/main/java/org/jenkinsci/plugin/gitea/GiteaSCMBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ public GiteaSCMBuilder(@NonNull GiteaSCMSource source,
} else if (head instanceof TagSCMHead) {
withRefSpec("+refs/tags/" + head.getName() + ":refs/tags/@{remote}/" + head.getName());
repoUrl = repositoryUrl(repoOwner, repository);
} else if (head instanceof ReleaseSCMHead) {
withRefSpec("+refs/tags/" + head.getName() + ":refs/tags/@{remote}/" + head.getName());
Mai-Lapyst marked this conversation as resolved.
Show resolved Hide resolved
repoUrl = repositoryUrl(repoOwner, repository);
} else {
withRefSpec("+refs/heads/" + head.getName() + ":refs/remotes/@{remote}/" + head.getName());
repoUrl = repositoryUrl(repoOwner, repository);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ protected GiteaSCMFileSystem(GiteaConnection connection, GiteaRepository repo, S
this.ref = ((BranchSCMRevision) rev).getHash();
} else if (rev instanceof TagSCMRevision) {
this.ref = ((TagSCMRevision) rev).getHash();
} else if (rev instanceof ReleaseSCMRevision) {
this.ref = ((ReleaseSCMRevision) rev).getHash();
} else {
this.ref = ref;
}
Expand Down Expand Up @@ -142,6 +144,10 @@ public SCMFileSystem build(@NonNull SCMSource source, @NonNull SCMHead head, @Ch
repoOwner = src.getRepoOwner();
repository = src.getRepository();
ref = head.getName();
} else if (head instanceof ReleaseSCMHead) {
repoOwner = src.getRepoOwner();
repository = src.getRepository();
ref = head.getName();
} else {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public class GiteaSCMNavigator extends SCMNavigator {
private final String serverUrl;
private final String repoOwner;
private String credentialsId;
private List<SCMTrait<?>> traits = new ArrayList<>();
private List<SCMTrait<? extends SCMTrait<?>>> traits = new ArrayList<>();
private GiteaOwner giteaOwner;

@DataBoundConstructor
Expand All @@ -118,7 +118,7 @@ public void setCredentialsId(String credentialsId) {
}

@NonNull
public List<SCMTrait<?>> getTraits() {
public List<SCMTrait<? extends SCMTrait<?>>> getTraits() {
return Collections.unmodifiableList(traits);
}

Expand Down
59 changes: 57 additions & 2 deletions src/main/java/org/jenkinsci/plugin/gitea/GiteaSCMSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
import org.jenkinsci.plugin.gitea.client.api.GiteaIssueState;
import org.jenkinsci.plugin.gitea.client.api.GiteaOwner;
import org.jenkinsci.plugin.gitea.client.api.GiteaPullRequest;
import org.jenkinsci.plugin.gitea.client.api.GiteaRelease;
import org.jenkinsci.plugin.gitea.client.api.GiteaRepository;
import org.jenkinsci.plugin.gitea.client.api.GiteaTag;
import org.jenkinsci.plugin.gitea.client.api.GiteaVersion;
Expand Down Expand Up @@ -261,6 +262,11 @@ protected SCMRevision retrieve(@NonNull SCMHead head, @NonNull TaskListener list
listener.getLogger().format("Pull request #%s is CLOSED%n", h.getId());
return null;
}
} else if (head instanceof ReleaseSCMHead) {
ReleaseSCMHead h = (ReleaseSCMHead) head;
final GiteaTag tag = c.fetchTag(repoOwner, repository, h.getName());
String revision = tag.getCommit().getSha();
return new ReleaseSCMRevision(new ReleaseSCMHead(h.getName(), h.getId()), revision);
} else {
listener.getLogger().format("Unknown head: %s of type %s%n", head.getName(), head.getClass().getName());
return null;
Expand Down Expand Up @@ -306,6 +312,9 @@ protected void retrieve(SCMSourceCriteria criteria, @NonNull SCMHeadObserver obs
request.setTags(c.fetchTags(giteaRepository));
}
}
if (request.isFetchReleases()) {
request.setReleases(c.fetchReleases(giteaRepository, false, request.isIncludingPreReleases()));
}

if (request.isFetchBranches()) {
int count = 0;
Expand Down Expand Up @@ -450,6 +459,33 @@ protected void retrieve(SCMSourceCriteria criteria, @NonNull SCMHeadObserver obs
}
listener.getLogger().format("%n %d tags were processed%n", count);
}
if (request.isFetchReleases()) {
int count = 0;
listener.getLogger().format("%n Checking releases...%n");
for (final GiteaRelease release : request.getReleases()) {
count++;
Mai-Lapyst marked this conversation as resolved.
Show resolved Hide resolved
listener.getLogger().format("%n Checking release '%s' (tag %s)%n",
release.getName(),
HyperlinkNote.encodeTo(
UriTemplate.buildFromTemplate(giteaRepository.getHtmlUrl())
.literal("/src/tag")
.path("tag")
.build()
.set("tag", release.getTagName())
.expand(),
release.getTagName()
)
);
final GiteaTag releaseTag = c.fetchTag(giteaRepository, release.getTagName());
final ReleaseSCMHead head = new ReleaseSCMHead(release.getTagName(), release.getId());
final ReleaseSCMRevision revision = new ReleaseSCMRevision(head, releaseTag.getCommit().getSha());
if (request.process(head, revision, this::createProbe, new CriteriaWitness<>(listener))) {
listener.getLogger().format("%n %d releases were processed (query completed)%n", count);
return;
}
}
listener.getLogger().format("%n %d releases were processed%n", count);
}
}
}
}
Expand Down Expand Up @@ -548,6 +584,24 @@ protected List<Action> retrieveActions(@NonNull SCMHead head, SCMHeadEvent event
pullUrl
));
result.add(new GiteaLink("icon-gitea-branch", pullUrl));
} else if (head instanceof ReleaseSCMHead) {
String releaseUrl = UriTemplate.buildFromTemplate(serverUrl)
.path(UriTemplateBuilder.var("owner"))
.path(UriTemplateBuilder.var("repository"))
.literal("/releases")
.literal("/tag")
.path(UriTemplateBuilder.var("name"))
.build()
.set("owner", repoOwner)
.set("repository", repository)
.set("name", head.getName())
.expand();
result.add(new ObjectMetadataAction(
null,
null,
releaseUrl
));
result.add(new GiteaLink("icon-gitea-logo", releaseUrl));
}
return result;
}
Expand Down Expand Up @@ -666,7 +720,7 @@ public void afterSave() {
GiteaWebhookListener.register(getOwner(), this, mode, credentialsId);
}

/*package*/ Gitea gitea() throws AbortException {
public Gitea gitea() throws AbortException {
GiteaServer server = GiteaServers.get().findServer(serverUrl);
if (server == null) {
throw new AbortException("Unknown server: " + serverUrl);
Expand Down Expand Up @@ -973,7 +1027,8 @@ protected SCMHeadCategory[] createCategories() {
return new SCMHeadCategory[]{
new UncategorizedSCMHeadCategory(Messages._GiteaSCMSource_UncategorizedCategory()),
new ChangeRequestSCMHeadCategory(Messages._GiteaSCMSource_ChangeRequestCategory()),
new TagSCMHeadCategory(Messages._GiteaSCMSource_TagCategory())
new TagSCMHeadCategory(Messages._GiteaSCMSource_TagCategory()),
new ReleaseSCMHeadCategory(Messages._GiteaSCMSource_ReleaseCategory())
};
}
}
Expand Down
Loading
Loading