├── webapp ├── src │ ├── react-app-env.d.ts │ ├── Contants.ts │ ├── index.tsx │ ├── hooks │ │ └── useStores.ts │ ├── components │ │ ├── TableCell.tsx │ │ ├── DeleteButton.tsx │ │ ├── Button.tsx │ │ ├── Header.tsx │ │ ├── formComponents │ │ │ ├── Checkbox.tsx │ │ │ ├── TextArea.tsx │ │ │ ├── FormList.tsx │ │ │ ├── RPMLimitationForm.tsx │ │ │ ├── TextInput.tsx │ │ │ ├── Select.tsx │ │ │ ├── MultiSelect.tsx │ │ │ ├── FileRequirementsForm.tsx │ │ │ ├── AddComponent.tsx │ │ │ ├── LimitationForm.tsx │ │ │ ├── PlatformProviderForm.tsx │ │ │ └── JDKVersionSelectForm.tsx │ │ ├── ConfirmDialog.tsx │ │ └── TreeNode.tsx │ ├── App.test.tsx │ ├── styles │ │ ├── Button.css │ │ ├── Forms.css │ │ └── Layout.css │ ├── index.css │ ├── utils │ │ ├── createVariantMap.ts │ │ └── createJobName.ts │ ├── stores │ │ └── index.ts │ ├── App.tsx │ └── logo.svg ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── logo192.png │ ├── logo512.png │ └── index.html ├── tsconfig.json └── package.json ├── fake-koji └── src │ ├── main │ ├── resources │ │ └── jenkins-templates │ │ │ ├── providers.xml │ │ │ ├── nested-view-columns.xml │ │ │ ├── shell-script.xml │ │ │ ├── trigger.xml │ │ │ ├── post-build-task-plugin.xml │ │ │ ├── provider.xml │ │ │ ├── view-columns.xml │ │ │ ├── fakekoji-xml-rpc-api.xml │ │ │ ├── koji-xml-rpc-api.xml │ │ │ ├── nested-view.xml │ │ │ ├── post-build-task-plugin-analyse.xml │ │ │ ├── timeoutedshell-script.xml │ │ │ ├── post-build-task-plugin-destroyvm.xml │ │ │ ├── view.xml │ │ │ ├── task-job.xml │ │ │ ├── pull-job.xml │ │ │ └── update-vm-job.xml │ └── java │ │ └── org │ │ └── fakekoji │ │ ├── jobmanager │ │ ├── model │ │ │ ├── NamesProvider.java │ │ │ ├── JobBump.java │ │ │ ├── PlatformBumpVariant.java │ │ │ ├── JobCollisionAction.java │ │ │ ├── JobConfiguration.java │ │ │ ├── Product.java │ │ │ ├── TestJobConfiguration.java │ │ │ ├── JobUpdateResult.java │ │ │ ├── TaskConfig.java │ │ │ ├── BuildPlatformConfig.java │ │ │ ├── PlatformConfig.java │ │ │ └── JDKTestProject.java │ │ ├── Parser.java │ │ ├── ManagementException.java │ │ ├── Manager.java │ │ ├── OToolUtils.java │ │ ├── ManagementUtils.java │ │ ├── ManagementResult.java │ │ ├── JobUpdater.java │ │ ├── bumpers │ │ │ └── BumpResult.java │ │ ├── views │ │ │ └── VersionlessPlatform.java │ │ └── manager │ │ │ ├── JDKVersionManager.java │ │ │ ├── BuildProviderManager.java │ │ │ ├── TaskManager.java │ │ │ └── PlatformManager.java │ │ ├── storage │ │ ├── StorageException.java │ │ └── Storage.java │ │ ├── core │ │ ├── DummyMain.java │ │ └── utils │ │ │ ├── matrix │ │ │ ├── cell │ │ │ │ ├── Cell.java │ │ │ │ ├── TitleCell.java │ │ │ │ ├── UpperCornerCell.java │ │ │ │ ├── MultiUrlCell.java │ │ │ │ ├── UrlCell.java │ │ │ │ └── CellGroup.java │ │ │ ├── TestEqualityFilter.java │ │ │ ├── BuildEqualityFilter.java │ │ │ ├── EqualityFilter.java │ │ │ ├── formatter │ │ │ │ ├── Formatter.java │ │ │ │ └── PlainTextFormatter.java │ │ │ ├── TestSpec.java │ │ │ └── BuildSpec.java │ │ │ ├── DirFilter.java │ │ │ └── FileFileFilter.java │ │ ├── api │ │ └── http │ │ │ ├── rest │ │ │ ├── OToolError.java │ │ │ ├── args │ │ │ │ ├── RemoveTaskVariantArgs.java │ │ │ │ └── BumpArgs.java │ │ │ └── RestUtils.java │ │ │ └── filehandling │ │ │ └── FileDownloadService.java │ │ ├── functional │ │ ├── Tuple.java │ │ └── Result.java │ │ └── model │ │ ├── JDKVersion.java │ │ ├── BuildProvider.java │ │ └── TaskVariantValue.java │ └── test │ ├── resources │ └── org │ │ └── fakekoji │ │ ├── jobmanager │ │ └── simple_job │ │ └── core │ │ └── utils │ │ └── matrix │ │ └── filtered_matrix │ └── java │ └── org │ └── fakekoji │ └── jobmanager │ └── project │ ├── JDKProjectParserTest.java │ └── ReverseJDKProjectParserTest.java ├── jenkins-scm-koji-plugin └── src │ └── main │ ├── resources │ ├── hudson │ │ └── plugins │ │ │ └── scm │ │ │ └── koji │ │ │ ├── KojiSCM │ │ │ ├── help-maxPreviousBuilds.html │ │ │ ├── help-dirPerNvr.html │ │ │ ├── help-downloadDir.html │ │ │ ├── help-cleanDownloadDir.html │ │ │ ├── global.jelly │ │ │ ├── help-KojiSCMConfig_skipPoolingIfJobRuns.html │ │ │ ├── help-KojiSCMConfig_requireWorkspace.html │ │ │ └── config.jelly │ │ │ ├── RealKojiXmlRpcApi │ │ │ ├── help-arch.html │ │ │ ├── help-tag.html │ │ │ ├── help-subpackageBlacklist.html │ │ │ ├── help-subpackageWhitelist.html │ │ │ ├── help-packageName.html │ │ │ └── config.jelly │ │ │ ├── KojiBuildProvider │ │ │ ├── help-downloadUrl.html │ │ │ ├── help-topUrl.html │ │ │ └── config.jelly │ │ │ ├── KojiScmRe │ │ │ └── index.jelly │ │ │ ├── FakeKojiXmlRpcApi │ │ │ └── config.jelly │ │ │ └── KojiChangeLogSet │ │ │ ├── index.jelly │ │ │ └── digest.jelly │ └── index.jelly │ └── java │ └── hudson │ └── plugins │ └── scm │ └── koji │ ├── KojiRepositoryBrowser.java │ ├── KojiRevisionState.java │ ├── KojiChangeLogParser.java │ ├── KojiRevisionFromBuild.java │ ├── model │ └── KojiBuildDownloadResult.java │ ├── KojiXmlRpcApiType.java │ ├── LoggerHelp.java │ ├── client │ └── FakeKojiBuildMatcher.java │ ├── KojiScmRe.java │ ├── KojiXmlRpcApi.java │ ├── KojiEnvVarsAction.java │ └── BuildsSerializer.java ├── koji-scm-lib ├── src │ ├── main │ │ └── java │ │ │ ├── hudson │ │ │ └── plugins │ │ │ │ └── scm │ │ │ │ └── koji │ │ │ │ ├── client │ │ │ │ ├── TaskListenerLogTransporter.java │ │ │ │ └── GlobPredicate.java │ │ │ │ └── model │ │ │ │ └── BuildProvider.java │ │ │ └── org │ │ │ └── fakekoji │ │ │ └── xmlrpc │ │ │ └── server │ │ │ ├── expensiveobjectscache │ │ │ ├── OriginalObjectProvider.java │ │ │ └── CachableRequest.java │ │ │ ├── JavaServerConstants.java │ │ │ ├── xmlrpcresponse │ │ │ ├── PackageId.java │ │ │ ├── FakeBuildDetail.java │ │ │ ├── XmlRpcResponse.java │ │ │ ├── FakeBuildList.java │ │ │ ├── TagSet.java │ │ │ ├── ArchiveList.java │ │ │ └── RPMList.java │ │ │ └── xmlrpcrequestparams │ │ │ ├── ListRPMs.java │ │ │ ├── ListArchives.java │ │ │ ├── XmlRpcRequestUtils.java │ │ │ ├── GetPackageId.java │ │ │ ├── XmlRpcRequestParams.java │ │ │ ├── GetBuildDetail.java │ │ │ ├── ListTags.java │ │ │ ├── ListBuilds.java │ │ │ ├── ListArtefacts.java │ │ │ └── GetBuildList.java │ └── test │ │ └── java │ │ └── hudson │ │ └── plugins │ │ └── scm │ │ └── koji │ │ └── LocalDateTimeWithDateTimeFormatterTest.java └── pom.xml ├── .gitignore ├── LICENSE ├── .github └── workflows │ └── maven.yml └── pom.xml /webapp/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /webapp/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /webapp/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/judovana/jenkins-scm-koji-plugin/master/webapp/public/favicon.ico -------------------------------------------------------------------------------- /webapp/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/judovana/jenkins-scm-koji-plugin/master/webapp/public/logo192.png -------------------------------------------------------------------------------- /webapp/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/judovana/jenkins-scm-koji-plugin/master/webapp/public/logo512.png -------------------------------------------------------------------------------- /webapp/src/Contants.ts: -------------------------------------------------------------------------------- 1 | const Constants = { 2 | TREE_PADDING_OFFSET: 30 3 | }; 4 | 5 | export default Constants; 6 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/providers.xml: -------------------------------------------------------------------------------- 1 | 2 | %{BUILD_PROVIDERS} 3 | 4 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/nested-view-columns.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /webapp/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import ReactDOM from "react-dom" 3 | 4 | import "./index.css" 5 | import App from "./App" 6 | 7 | ReactDOM.render(, document.getElementById("root")) 8 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/KojiSCM/help-maxPreviousBuilds.html: -------------------------------------------------------------------------------- 1 |
2 | Max number of previous builds to check, in case there are more old builds available. 3 |
4 | -------------------------------------------------------------------------------- /webapp/src/hooks/useStores.ts: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { stores } from "../stores" 3 | 4 | const useStores = () => React.useContext(React.createContext(stores)) 5 | export default useStores 6 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/RealKojiXmlRpcApi/help-arch.html: -------------------------------------------------------------------------------- 1 |
2 | Only use builds containing RPMs for specified arches. May be empty. Coma-separated list is expected. 3 |
4 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/hudson/plugins/scm/koji/client/TaskListenerLogTransporter.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.scm.koji.client; 2 | 3 | public interface TaskListenerLogTransporter { 4 | public void println(String s); 5 | } 6 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/KojiSCM/help-dirPerNvr.html: -------------------------------------------------------------------------------- 1 |
2 | Create subdirectory under the download dir, where name of the directory will be the NVR of the RPM package. 3 |
4 | 5 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/model/NamesProvider.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.model; 2 | 3 | public interface NamesProvider { 4 | 5 | public String getName(); 6 | public String getShortName(); 7 | } 8 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/shell-script.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #!/bin/bash 4 | %{EXPORTED_VARIABLES} 5 | bash %{RUN_SCRIPT} '%{TASK_SCRIPT}' 6 | 7 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/KojiSCM/help-downloadDir.html: -------------------------------------------------------------------------------- 1 |
2 | Directory inside workspace to download RPM packages to. If empty the RPMs will be downloaded directly into workspace. 3 |
4 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/Parser.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager; 2 | 3 | import org.fakekoji.storage.StorageException; 4 | 5 | public interface Parser { 6 | 7 | U parse(T t) throws ManagementException, StorageException; 8 | } 9 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/storage/StorageException.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.storage; 2 | 3 | 4 | public class StorageException extends Exception { 5 | 6 | public StorageException(String message) { 7 | super(message); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/trigger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | %{SCM_POLL_SCHEDULE} 4 | false 5 | 6 | 7 | -------------------------------------------------------------------------------- /webapp/src/components/TableCell.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { TableCell as MUITableCell } from "@material-ui/core" 3 | 4 | const TableCell: React.FC = ({ children }) => { 5 | return {children} 6 | } 7 | 8 | export default TableCell 9 | -------------------------------------------------------------------------------- /webapp/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/post-build-task-plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | %{POST_BUILD_TASK_PLUGIN_DESTROYVM} 4 | %{POST_BUILD_TASK_PLUGIN_ANALYSE} 5 | 6 | 7 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/provider.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | %{BUILD_PROVIDER_TOP_URL} 4 | %{BUILD_PROVIDER_DOWNLOAD_URL} 5 | 6 | 7 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/DummyMain.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.core; 2 | 3 | //Please do not delete this, untill we make yarn to work in contianer 4 | 5 | public class DummyMain { 6 | public static void main(String[] args) { 7 | System.out.println("Fake koji is on classapth"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/api/http/rest/OToolError.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.api.http.rest; 2 | 3 | public class OToolError { 4 | final String message; 5 | final int code; 6 | 7 | public OToolError(String message, int code) { 8 | this.message = message; 9 | this.code = code; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | This is plugin able to pull binaries to jenkins from koji-like services. 4 | By default it contains api for http://koji.fedoraproject.org/ and for internal fake-koji server (which have its own api on top of real-koji like api) 5 |
6 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/KojiBuildProvider/help-downloadUrl.html: -------------------------------------------------------------------------------- 1 |
2 | URL for RPM download. For example:
3 | http://koji.fedoraproject.org/packages/:
4 | http://custom.koji:DPORT/
5 |
6 | 7 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/KojiSCM/help-cleanDownloadDir.html: -------------------------------------------------------------------------------- 1 |
2 | Remove all the contents of the download directory before the download.
3 | NOTE:  this option is ignored if Download directory field is empty and subdirectory for NVR is not checked. 4 |
5 | 6 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/expensiveobjectscache/OriginalObjectProvider.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.expensiveobjectscache; 2 | 3 | import org.fakekoji.xmlrpc.server.xmlrpcrequestparams.XmlRpcRequestParams; 4 | 5 | public interface OriginalObjectProvider { 6 | 7 | Object obtainOriginal(String url, XmlRpcRequestParams params); 8 | } 9 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/utils/matrix/cell/Cell.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.core.utils.matrix.cell; 2 | 3 | public interface Cell { 4 | default boolean isEmpty() { 5 | return false; 6 | } 7 | 8 | default int getSpan() { 9 | return 1; 10 | } 11 | 12 | default int size() { 13 | return 1; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/expensiveobjectscache/CachableRequest.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.expensiveobjectscache; 2 | 3 | /** 4 | * This object can be cached in maps. Thus hashcode and equals are superimportant 5 | */ 6 | public interface CachableRequest { 7 | 8 | boolean equals(Object o); 9 | 10 | int hashCode(); 11 | } 12 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/view-columns.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /webapp/src/styles/Button.css: -------------------------------------------------------------------------------- 1 | .button { 2 | border: none; 3 | color: #fff; 4 | cursor: pointer; 5 | padding: 12px 16px; 6 | } 7 | 8 | .button-red { 9 | background-color: #d23; 10 | } 11 | 12 | .button-green { 13 | background-color: #2d3; 14 | } 15 | 16 | .button-blue { 17 | background-color: #23d 18 | } 19 | 20 | .button-gray { 21 | background-color: #999; 22 | } 23 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/fakekoji-xml-rpc-api.xml: -------------------------------------------------------------------------------- 1 | 2 | FAKE_KOJI 3 | %{PROJECT_NAME} 4 | %{BUILD_VARIANTS} 5 | %{PLATFORM} 6 | %{IS_BUILT} 7 | 8 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/KojiBuildProvider/help-topUrl.html: -------------------------------------------------------------------------------- 1 |
2 | URL of kojihub or brewhub. For example:
3 | http://koji.fedoraproject.org/kojihub:
4 | In case of more providers, first found first served.
5 | http://custom.koji:XPORT/RPC2/
6 |
7 | -------------------------------------------------------------------------------- /webapp/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/utils/matrix/TestEqualityFilter.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.core.utils.matrix; 2 | 3 | public class TestEqualityFilter extends EqualityFilter{ 4 | 5 | public final boolean suite; 6 | 7 | public TestEqualityFilter(boolean os, boolean arch, boolean provider, boolean suite, boolean variants) { 8 | super(os, arch, provider, variants); 9 | this.suite = suite; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/RealKojiXmlRpcApi/help-tag.html: -------------------------------------------------------------------------------- 1 |
2 | Use only builds containing specified tag.
3 | May be empty to match all the builds.
4 | Supports space separated regex patterns 5 |
test page
spec 6 |
7 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/koji-xml-rpc-api.xml: -------------------------------------------------------------------------------- 1 | 2 | REAL_KOJI 3 | %{PACKAGE_NAME} 4 | %{ARCH} 5 | %{TAGS} 6 | %{SUBPACKAGE_BLACKLIST} 7 | %{SUBPACKAGE_WHITELIST} 8 | 9 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/JavaServerConstants.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server; 2 | 3 | public class JavaServerConstants { 4 | public static final int DFAULT_RP2C_PORT = 9848; 5 | public static final int DFAULT_DWNLD_PORT = DFAULT_RP2C_PORT + 1; 6 | public static final int DFAULT_SCP_PORT = 9822; 7 | public static final int DFAULT_WEBAP_PORT = 8888; 8 | public static final String FAKE_KOJI_LOGGER = "Fake-Koji"; 9 | } 10 | -------------------------------------------------------------------------------- /webapp/src/utils/createVariantMap.ts: -------------------------------------------------------------------------------- 1 | import { TaskVariant } from "../stores/model" 2 | 3 | const createTaskVariantsMap = ( 4 | taskVariants: TaskVariant[], 5 | filter: (variant: TaskVariant) => boolean 6 | ): { [key: string]: string } => 7 | taskVariants.filter(filter).reduce((map, taskVariant) => { 8 | map[taskVariant.id] = taskVariant.defaultValue 9 | return map 10 | }, {} as { [key: string]: string }) 11 | 12 | export default createTaskVariantsMap 13 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/storage/Storage.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.storage; 2 | 3 | import java.util.List; 4 | 5 | public interface Storage { 6 | 7 | void store(String id, T t) throws StorageException; 8 | 9 | void delete(String id) throws StorageException; 10 | 11 | T load(String id, Class valueType) throws StorageException; 12 | 13 | List loadAll(Class valueType) throws StorageException; 14 | 15 | boolean contains(String id); 16 | } 17 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/ManagementException.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager; 2 | 3 | public class ManagementException extends Exception { 4 | 5 | public ManagementException(String message) { 6 | super(message); 7 | } 8 | 9 | public ManagementException(Exception exception) { 10 | super(exception); 11 | } 12 | 13 | public ManagementException(String message, Exception exception) { 14 | super(message, exception); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/java/hudson/plugins/scm/koji/KojiRepositoryBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.scm.koji; 2 | 3 | import hudson.scm.ChangeLogSet; 4 | import hudson.scm.RepositoryBrowser; 5 | import java.io.IOException; 6 | import java.net.URL; 7 | 8 | public class KojiRepositoryBrowser extends RepositoryBrowser { 9 | 10 | @Override 11 | public URL getChangeSetLink(ChangeLogSet.Entry changeSet) throws IOException { 12 | // TODO implement 13 | return null; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/nested-view.xml: -------------------------------------------------------------------------------- 1 | 2 | %{VIEW_NAME} 3 | true 4 | true 5 | 6 | 7 | %{SUBVIEWS} 8 | 9 | 10 | 11 | %{NESTEDVIEW_COLUMNS} 12 | 13 | 14 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/RealKojiXmlRpcApi/help-subpackageBlacklist.html: -------------------------------------------------------------------------------- 1 |
2 | space separated Regex patterns for subpackages not to download. This is applied first, before whitelist. For example:
3 | .*debug.* .*accessibility.* .*src.* .*demo.* 4 |
test page
spec 5 |
6 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/utils/matrix/BuildEqualityFilter.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.core.utils.matrix; 2 | 3 | public class BuildEqualityFilter extends EqualityFilter { 4 | 5 | public final boolean project; 6 | public final boolean jdk; 7 | 8 | 9 | public BuildEqualityFilter(boolean os, boolean arch, boolean provider, boolean project, boolean jdk, boolean variants) { 10 | super(os, arch, provider, variants); 11 | this.project = project; 12 | this.jdk = jdk; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/RealKojiXmlRpcApi/help-subpackageWhitelist.html: -------------------------------------------------------------------------------- 1 |
2 | space separated Regex patterns for subpackages to download. This is applied last, after exclude list. This has no effect when empty. For 3 | example:
4 | *.x86_64.win.zip$ 5 |
test page
spec 6 |
7 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/utils/matrix/EqualityFilter.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.core.utils.matrix; 2 | 3 | abstract class EqualityFilter { 4 | 5 | public final boolean os; 6 | public final boolean arch; 7 | public final boolean provider; 8 | public final boolean variants; 9 | 10 | public EqualityFilter(boolean os, boolean arch, boolean provider, boolean variants) { 11 | this.os = os; 12 | this.arch = arch; 13 | this.provider = provider; 14 | this.variants = variants; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /webapp/src/stores/index.ts: -------------------------------------------------------------------------------- 1 | import { createBrowserHistory } from "history" 2 | 3 | import { ConfigStore } from "./ConfigStore" 4 | import ConfigService from "./services/ConfigService" 5 | import { ViewStore } from "./ViewStore" 6 | 7 | const history = createBrowserHistory() 8 | const url = window.location.origin 9 | 10 | const service = new ConfigService(url) 11 | 12 | const configStore = new ConfigStore(service) 13 | const viewStore = new ViewStore(history, configStore) 14 | 15 | export const stores = { 16 | configStore, 17 | viewStore 18 | } 19 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/RealKojiXmlRpcApi/help-packageName.html: -------------------------------------------------------------------------------- 1 |
2 | Exact package name to watch, or space delimited list of packages to match
3 | Note, that multi-package works only for old api, and may not work as expected.
4 | the builds of all space split packages are obtained and fitlered, and the logic is applied to the merged list.
5 | So for eg "A B" if package A have 10 very old builds, and package B ten very new builds, only builds of B will be processed.
6 | If you suddenly build A, then it willbe of course pulled. 7 |
8 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/java/hudson/plugins/scm/koji/KojiRevisionState.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.scm.koji; 2 | 3 | import hudson.plugins.scm.koji.model.Build; 4 | import hudson.scm.SCMRevisionState; 5 | 6 | public class KojiRevisionState extends SCMRevisionState { 7 | 8 | private final Build build; 9 | 10 | public KojiRevisionState(Build build) { 11 | this.build = build; 12 | } 13 | 14 | public Build getBuild() { 15 | return build; 16 | } 17 | 18 | @Override 19 | public String toString() { 20 | return "KojiRevisionState[nvr=" + build + "]"; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ 2 | /nbproject/ 3 | .idea/ 4 | *.iml 5 | /koji-scm-lib/target/ 6 | /jenkins-scm-koji-plugin/target/ 7 | /fake-koji/target/ 8 | /jenkins-scm-koji-plugin/work 9 | 10 | # webapp 11 | # dependencies 12 | webapp/node_modules 13 | webapp/.pnp 14 | webapp/.pnp.js 15 | 16 | # testing 17 | webapp/coverage 18 | 19 | # production 20 | webapp/build 21 | 22 | # maven 23 | webapp/node 24 | 25 | # misc 26 | webapp/.DS_Store 27 | webapp/.env.local 28 | webapp/.env.development.local 29 | webapp/.env.test.local 30 | webapp/.env.production.local 31 | 32 | webapp/npm-debug.log* 33 | webapp/yarn-debug.log* 34 | webapp/yarn-error.log* 35 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/Manager.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager; 2 | 3 | import org.fakekoji.storage.StorageException; 4 | 5 | import java.util.List; 6 | 7 | public interface Manager { 8 | 9 | T create(T t) throws StorageException, ManagementException; 10 | 11 | T read(String id) throws StorageException, ManagementException; 12 | 13 | List readAll() throws StorageException; 14 | 15 | T update(String id, T t) throws StorageException, ManagementException; 16 | 17 | T delete(String id) throws StorageException, ManagementException; 18 | 19 | boolean contains(String id); 20 | } 21 | -------------------------------------------------------------------------------- /fake-koji/src/test/resources/org/fakekoji/jobmanager/simple_job: -------------------------------------------------------------------------------- 1 | 2 | 3 | created by java test 4 | false 5 | 6 | 7 | true 8 | false 9 | false 10 | false 11 | 12 | false 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/KojiSCM/global.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/KojiScmRe/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

Hello!

6 |

Unluckily this - via root action - do not work for now. It must be done via build-targeted action, whcihc somehow takes (our nvr)build as parameter, and then acts

7 |
8 |
9 |
10 | -------------------------------------------------------------------------------- /webapp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "experimentalDecorators": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/post-build-task-plugin-analyse.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | .* 5 | OR 6 | 7 | 8 | false 9 | false 10 | 11 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/timeoutedshell-script.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | %{TIMEOUT_MINUTES} 4 | 5 | 6 | 7 | #!/bin/bash 8 | %{EXPORTED_VARIABLES} 9 | bash %{RUN_SCRIPT} '%{TASK_SCRIPT}' 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcresponse/PackageId.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcresponse; 2 | 3 | public class PackageId implements XmlRpcResponse { 4 | 5 | private final Integer packageId; 6 | 7 | public PackageId(Integer packageId) { 8 | this.packageId = packageId; 9 | } 10 | 11 | @Override 12 | public Object toObject() { 13 | return packageId; 14 | } 15 | 16 | @Override 17 | public Integer getValue() { 18 | return packageId; 19 | } 20 | 21 | public static PackageId create(Object object) { 22 | return new PackageId((Integer) object); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /webapp/src/components/DeleteButton.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { IconButton } from "@material-ui/core" 3 | import { Delete } from "@material-ui/icons" 4 | 5 | import useStores from "../hooks/useStores" 6 | 7 | interface DeleteButtonProps { 8 | onClick: () => void 9 | } 10 | 11 | const DeleteButton: React.FC = ({ onClick }) => { 12 | const { viewStore } = useStores() 13 | const { confirm } = viewStore 14 | const _onClick = () => confirm("Are you sure to delete?", onClick) 15 | return ( 16 | 17 | 18 | 19 | ) 20 | } 21 | 22 | export default DeleteButton 23 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/post-build-task-plugin-destroyvm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | .* 5 | OR 6 | 7 | 8 | true 9 | false 10 | 11 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcresponse/FakeBuildDetail.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcresponse; 2 | 3 | import hudson.plugins.scm.koji.model.Build; 4 | 5 | public class FakeBuildDetail implements XmlRpcResponse { 6 | 7 | private final Build build; 8 | 9 | public FakeBuildDetail(Build build) { 10 | this.build = build; 11 | } 12 | 13 | @Override 14 | public Object toObject() { 15 | return this; 16 | } 17 | 18 | @Override 19 | public Build getValue() { 20 | return build; 21 | } 22 | 23 | public static FakeBuildDetail create(Object object) { 24 | return (FakeBuildDetail) object; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/utils/matrix/formatter/Formatter.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.core.utils.matrix.formatter; 2 | 3 | import org.fakekoji.core.utils.matrix.cell.CellGroup; 4 | import org.fakekoji.core.utils.matrix.cell.TitleCell; 5 | import org.fakekoji.core.utils.matrix.cell.UpperCornerCell; 6 | 7 | public interface Formatter { 8 | String rowStart(); 9 | 10 | String rowEnd(); 11 | 12 | String tableStart(); 13 | 14 | String tableEnd(); 15 | 16 | String edge(final TitleCell titleCell, int span); 17 | 18 | String cells(final CellGroup cellGroup, int maxInColumn, final String rowTitle, final String colTitle); 19 | 20 | String upperCorner(final UpperCornerCell cell); 21 | 22 | String lowerCorner(int total, int i, int span); 23 | } 24 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/model/JobBump.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.model; 2 | 3 | public class JobBump { 4 | public final Job from; 5 | public final Job to; 6 | public final boolean isCollision; 7 | 8 | public JobBump(Job from, Job to, boolean isCollision) { 9 | this.from = from; 10 | this.to = to; 11 | this.isCollision = isCollision; 12 | } 13 | 14 | @Override 15 | public String toString() { 16 | return "JobBump{" + 17 | "from=" + from + 18 | ", to=" + to + 19 | ", isCollision=" + isCollision + 20 | '}'; 21 | } 22 | 23 | public String toNiceString() { 24 | return to + " (from:" + to + "/" + isCollision + ")"; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/java/hudson/plugins/scm/koji/KojiChangeLogParser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.scm.koji; 2 | 3 | import hudson.model.Run; 4 | import hudson.plugins.scm.koji.model.Build; 5 | import hudson.scm.ChangeLogParser; 6 | import hudson.scm.ChangeLogSet; 7 | import hudson.scm.RepositoryBrowser; 8 | import java.io.File; 9 | import java.io.IOException; 10 | import org.xml.sax.SAXException; 11 | 12 | public class KojiChangeLogParser extends ChangeLogParser { 13 | 14 | @Override 15 | public ChangeLogSet parse(Run run, RepositoryBrowser browser, File changelogFile) throws IOException, SAXException { 16 | Build build = new BuildsSerializer().read(changelogFile); 17 | return new KojiChangeLogSet(build, run, browser); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/FakeKojiXmlRpcApi/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/java/hudson/plugins/scm/koji/KojiRevisionFromBuild.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.scm.koji; 2 | 3 | import hudson.FilePath; 4 | import hudson.plugins.scm.koji.model.Build; 5 | import hudson.remoting.VirtualChannel; 6 | import java.io.File; 7 | import java.io.IOException; 8 | import org.jenkinsci.remoting.RoleChecker; 9 | 10 | public class KojiRevisionFromBuild implements FilePath.FileCallable { 11 | 12 | @Override 13 | public Build invoke(File workspace, VirtualChannel channel) throws IOException, InterruptedException { 14 | Build build = new BuildsSerializer().read(new File(workspace, "changelog.xml")); 15 | return build; 16 | } 17 | 18 | @Override 19 | public void checkRoles(RoleChecker checker) throws SecurityException { 20 | // TODO maybe implement? 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/view.xml: -------------------------------------------------------------------------------- 1 | 2 | %{VIEW_NAME} 3 | 10 | true 11 | true 12 | 13 | 14 | 15 | 16 | 17 | 18 | %{COLUMNS} 19 | 20 | %{VIEW_REGEX} 21 | false 22 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcresponse/XmlRpcResponse.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcresponse; 2 | 3 | public interface XmlRpcResponse { 4 | 5 | 6 | /** 7 | * This method converts POJO to maps of objects or a simple object based on xml-rpc method it is used for. This 8 | * method is used in fake-koji xml-rpc api to send responses. 9 | * 10 | * @see RPMList 11 | * @see PackageId 12 | * 13 | * @return map of objects as Object 14 | */ 15 | Object toObject(); 16 | 17 | /** 18 | * This method converts a simple object or map of objects to POJO. It is reverse toXmlRpcParams method. This method is 19 | * used in xml-rpc client to receive responses 20 | * 21 | * @see RPMList 22 | * @see PackageId 23 | * 24 | * @return instance of requested type 25 | */ 26 | T getValue(); 27 | } 28 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/utils/matrix/cell/TitleCell.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.core.utils.matrix.cell; 2 | 3 | import java.util.Objects; 4 | 5 | public class TitleCell implements Cell { 6 | 7 | private final String title; 8 | 9 | public TitleCell(final String title) { 10 | this.title = title; 11 | } 12 | 13 | public String getTitle() { 14 | return title; 15 | } 16 | 17 | @Override 18 | public boolean equals(Object o) { 19 | if (this == o) return true; 20 | if (!(o instanceof TitleCell)) return false; 21 | TitleCell titleCell = (TitleCell) o; 22 | return Objects.equals(title, titleCell.title); 23 | } 24 | 25 | @Override 26 | public int hashCode() { 27 | return Objects.hash(title); 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return getTitle(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcrequestparams/ListRPMs.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcrequestparams; 2 | 3 | import hudson.plugins.scm.koji.Constants; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import static org.fakekoji.xmlrpc.server.xmlrpcrequestparams.XmlRpcRequestUtils.toMap; 9 | 10 | public class ListRPMs extends ListArtefacts { 11 | 12 | public ListRPMs(Integer buildId, List archs) { 13 | super(buildId, archs); 14 | } 15 | 16 | @Override 17 | public String getMethodName() { 18 | return Constants.listRPMs; 19 | } 20 | 21 | public static ListRPMs create(Object object) { 22 | final Map map = toMap(object); 23 | return new ListRPMs( 24 | (Integer) map.get(Constants.buildID), 25 | getArchs(map.get(Constants.arches)) 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/functional/Tuple.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.functional; 2 | 3 | import java.util.Objects; 4 | 5 | public class Tuple { 6 | public final X x; 7 | public final Y y; 8 | 9 | public Tuple(X x, Y y) { 10 | this.x = x; 11 | this.y = y; 12 | } 13 | 14 | @Override 15 | public boolean equals(Object o) { 16 | if (this == o) return true; 17 | if (!(o instanceof Tuple)) return false; 18 | Tuple tuple = (Tuple) o; 19 | return Objects.equals(x, tuple.x) && 20 | Objects.equals(y, tuple.y); 21 | } 22 | 23 | @Override 24 | public int hashCode() { 25 | return Objects.hash(x, y); 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | return "Tuple{" + 31 | "x=" + x + 32 | ", y=" + y + 33 | '}'; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/RealKojiXmlRpcApi/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/OToolUtils.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager; 2 | 3 | import java.io.File; 4 | 5 | public class OToolUtils { 6 | 7 | public static String createArchiveName( 8 | final File packageDir, 9 | final File versionDir, 10 | final File buildDir, 11 | final File archiveDir 12 | ) { 13 | return createArchiveName(packageDir.getName(), versionDir.getName(), buildDir.getName(), archiveDir.getName()); 14 | } 15 | 16 | public static String createArchiveName( 17 | final String packageName, 18 | final String version, 19 | final String build, 20 | final String archive 21 | ) { 22 | return String.join( 23 | "-", 24 | packageName, 25 | version, 26 | build + "." + archive + ".tarxz" 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcrequestparams/ListArchives.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcrequestparams; 2 | 3 | import hudson.plugins.scm.koji.Constants; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import static org.fakekoji.xmlrpc.server.xmlrpcrequestparams.XmlRpcRequestUtils.toMap; 9 | 10 | public class ListArchives extends ListArtefacts { 11 | 12 | public ListArchives(Integer buildId, List archs) { 13 | super(buildId, archs); 14 | } 15 | 16 | @Override 17 | public String getMethodName() { 18 | return Constants.listArchives; 19 | } 20 | 21 | public static ListArchives create(Object object) { 22 | final Map map = toMap(object); 23 | return new ListArchives( 24 | (Integer) map.get(Constants.buildID), 25 | getArchs(map.get(Constants.arches)) 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/api/http/rest/args/RemoveTaskVariantArgs.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.api.http.rest.args; 2 | 3 | import org.fakekoji.api.http.rest.OToolError; 4 | import org.fakekoji.functional.Result; 5 | 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import static org.fakekoji.api.http.rest.RestUtils.extractMandatoryParamValue; 10 | 11 | public class RemoveTaskVariantArgs extends BumpArgs { 12 | public final String name; 13 | 14 | RemoveTaskVariantArgs(final BumpArgs bumpArgs, final String name) { 15 | super(bumpArgs); 16 | this.name = name; 17 | } 18 | 19 | public static Result parse(final Map> params) { 20 | return parseBumpArgs(params).flatMap(bumpArgs -> extractMandatoryParamValue(params, "name").flatMap(name -> 21 | Result.ok(new RemoveTaskVariantArgs(bumpArgs, name)) 22 | )); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/java/hudson/plugins/scm/koji/model/KojiBuildDownloadResult.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.scm.koji.model; 2 | 3 | import java.util.List; 4 | 5 | public class KojiBuildDownloadResult implements java.io.Serializable { 6 | 7 | private final Build build; 8 | private final String rpmsDirectory; 9 | private final List rpmFiles; 10 | 11 | public KojiBuildDownloadResult(Build build, String rpmsDirectory, List rpmFiles) { 12 | this.build = build; 13 | this.rpmsDirectory = rpmsDirectory; 14 | this.rpmFiles = rpmFiles; 15 | } 16 | 17 | public boolean isEmpty() { 18 | return build == null || rpmFiles == null || rpmFiles.isEmpty(); 19 | } 20 | 21 | public Build getBuild() { 22 | return build; 23 | } 24 | 25 | public String getRpmsDirectory() { 26 | return rpmsDirectory; 27 | } 28 | 29 | public List getRpmFiles() { 30 | return rpmFiles; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/hudson/plugins/scm/koji/model/BuildProvider.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.scm.koji.model; 2 | 3 | import jakarta.xml.bind.annotation.XmlAccessType; 4 | import jakarta.xml.bind.annotation.XmlAccessorType; 5 | import jakarta.xml.bind.annotation.XmlElement; 6 | 7 | @XmlAccessorType(XmlAccessType.FIELD) 8 | public class BuildProvider implements java.io.Serializable { 9 | 10 | @XmlElement(name = "topUrl") 11 | private final String topUrl; 12 | 13 | @XmlElement(name = "downloadUrl") 14 | private final String downloadUrl; 15 | 16 | public BuildProvider() { 17 | topUrl = null; 18 | downloadUrl = null; 19 | } 20 | 21 | public BuildProvider(String topUrl, String downloadUrl) { 22 | this.topUrl = topUrl; 23 | this.downloadUrl = downloadUrl; 24 | } 25 | 26 | public String getTopUrl() { 27 | return topUrl; 28 | } 29 | 30 | public String getDownloadUrl() { 31 | return downloadUrl; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/java/hudson/plugins/scm/koji/KojiXmlRpcApiType.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.scm.koji; 2 | 3 | import java.io.Serializable; 4 | 5 | public enum KojiXmlRpcApiType implements Serializable { 6 | 7 | REAL_KOJI("realKoji"), 8 | FAKE_KOJI("fakeKoji"); 9 | 10 | private final String name; 11 | 12 | KojiXmlRpcApiType(final String xmlRpcApiName) { 13 | name = xmlRpcApiName; 14 | } 15 | 16 | @Override 17 | public String toString() { 18 | return getName(); 19 | } 20 | 21 | public String getName() { 22 | return name; 23 | } 24 | 25 | public static KojiXmlRpcApiType getType(final String value) { 26 | for (KojiXmlRpcApiType type : KojiXmlRpcApiType.values()) { 27 | if (type.getName().equals(value)) { 28 | return type; 29 | } 30 | } 31 | throw new IllegalArgumentException("Invalid type (" + value + ") requested for " 32 | + KojiXmlRpcApiType.class.getName()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/KojiSCM/help-KojiSCMConfig_skipPoolingIfJobRuns.html: -------------------------------------------------------------------------------- 1 |
2 |

If checked, the pooling is skipped (returning no chnages found) if jobs currently runs

3 |
    4 |
  • By default it is not selected
  • 5 |
  • It do not have much sense to have enabled both "require worksapce" and this
  • 6 |
  • it of course kill the can run in parallel feature
  • 7 |
  • General usecase is:
  • 8 |
      9 |
    • do not enable run in parallel with this feature
    • 10 |
    • all the troubels are with archiving of build.xml, it match with build nvr and usage of archved build.xml to rerun the nvr
    • 11 |
    • with worksapce on, soemtimes the poling got stuck, waiting for wrkscpae for hours
    • 12 |
    • this is avoiding this problem, but may have other consequences
    • 13 | 14 |
    15 |
  • this option is not exactly best tested, as is new
  • 16 |
17 |
18 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/utils/matrix/cell/UpperCornerCell.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.core.utils.matrix.cell; 2 | 3 | import java.util.List; 4 | import java.util.Objects; 5 | 6 | public class UpperCornerCell implements Cell { 7 | 8 | private final List projectCells; 9 | 10 | public UpperCornerCell(final List projectCells) { 11 | this.projectCells = projectCells; 12 | } 13 | 14 | public List projectCells() { 15 | return this.projectCells; 16 | } 17 | 18 | @Override 19 | public int getSpan() { 20 | return projectCells.size(); 21 | } 22 | 23 | @Override 24 | public boolean equals(Object o) { 25 | if (this == o) return true; 26 | if (!(o instanceof UpperCornerCell)) return false; 27 | UpperCornerCell that = (UpperCornerCell) o; 28 | return Objects.equals(projectCells, that.projectCells); 29 | } 30 | 31 | @Override 32 | public int hashCode() { 33 | return Objects.hash(projectCells); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcrequestparams/XmlRpcRequestUtils.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcrequestparams; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | public class XmlRpcRequestUtils { 9 | 10 | // this parameter allows XML-RPC contain non primitive data like maps 11 | static final String starStarLabel = "__starstar"; 12 | 13 | static Map toMap(Object object) { 14 | return (Map) object; 15 | } 16 | 17 | public static List> toMaps(Object object) { 18 | final Object[] objectArray = (Object[]) object; 19 | if (objectArray == null) { 20 | return null; 21 | } 22 | final List objects = Arrays.asList(objectArray); 23 | final List> maps = new ArrayList<>(objects.size()); 24 | for (Object o : objects) { 25 | maps.add(toMap(o)); 26 | } 27 | return maps; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/task-job.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | %{BUILD_PROVIDERS} 8 | %{XML_RPC_API} 9 | rpms 10 | true 11 | false 12 | 10 13 | 14 | %{NODES} 15 | false 16 | false 17 | false 18 | false 19 | %{TRIGGER} 20 | false 21 | 22 | %{BUILDER} 23 | 24 | 25 | %{POST_BUILD_TASKS} 26 | %{POST_BUILD_TASK_PLUGIN} 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/utils/matrix/cell/MultiUrlCell.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.core.utils.matrix.cell; 2 | 3 | import java.util.List; 4 | import java.util.Objects; 5 | 6 | public class MultiUrlCell extends TitleCell { 7 | 8 | private final List urls; 9 | 10 | public MultiUrlCell(final String title, final List urls) { 11 | super(title); 12 | this.urls = urls; 13 | } 14 | 15 | public List getUrls() { 16 | return urls; 17 | } 18 | 19 | @Override 20 | public int getSpan() { 21 | return this.urls.size(); 22 | } 23 | 24 | @Override 25 | public boolean equals(Object o) { 26 | if (this == o) return true; 27 | if (!(o instanceof MultiUrlCell)) return false; 28 | MultiUrlCell that = (MultiUrlCell) o; 29 | return Objects.equals(urls, that.urls); 30 | } 31 | 32 | @Override 33 | public int hashCode() { 34 | return Objects.hash(urls); 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return getTitle() + " " + urls; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /webapp/src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | import "../styles/Button.css" 4 | 5 | type ButtonColor = "red" | "green" | "gray" | "blue" 6 | 7 | type ButtonPropsOptional = { 8 | children: string | string[] | number | number[] 9 | onClick: () => void 10 | color: ButtonColor 11 | } 12 | 13 | type ButtonPropsRequired = { 14 | 15 | } 16 | 17 | type ButtonProps = ButtonPropsOptional & ButtonPropsRequired 18 | 19 | class Button extends React.PureComponent { 20 | 21 | static defaultProps: ButtonPropsOptional = { 22 | children: "", 23 | onClick: () => { }, 24 | color: "blue" 25 | } 26 | 27 | onClick = (event: React.MouseEvent) => { 28 | event.stopPropagation() 29 | this.props.onClick() 30 | } 31 | 32 | render() { 33 | const { children, color } = this.props 34 | return ( 35 |
38 | {children} 39 |
40 | ) 41 | } 42 | } 43 | 44 | export default Button 45 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/KojiBuildProvider/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 32 | 33 | 38 | 39 |
40 | 41 |
42 | 43 |
44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Stanislav Baiduzhyi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/model/PlatformBumpVariant.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.model; 2 | 3 | import org.fakekoji.functional.Result; 4 | 5 | import java.util.Arrays; 6 | import java.util.stream.Collectors; 7 | 8 | public enum PlatformBumpVariant { 9 | BUILD_ONLY("build_only"), 10 | TEST_ONLY("test_only"), 11 | BOTH("both"); 12 | 13 | public final String value; 14 | 15 | PlatformBumpVariant(final String value) { 16 | this.value = value; 17 | } 18 | 19 | public static String stringValues(final String delimiter) { 20 | return Arrays.stream(PlatformBumpVariant.values()) 21 | .map(variant -> variant.value) 22 | .collect(Collectors.joining(delimiter)); 23 | } 24 | 25 | public static Result parse(final String value) { 26 | try { 27 | return Result.ok(PlatformBumpVariant.valueOf(value.toUpperCase())); 28 | } catch (IllegalArgumentException e) { 29 | return Result.err("Invalid platform bump variant: " + value + ". Valid options are: " + stringValues(", ")); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/model/JobCollisionAction.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.model; 2 | 3 | import org.fakekoji.functional.Result; 4 | 5 | import java.util.Arrays; 6 | import java.util.stream.Collectors; 7 | 8 | public enum JobCollisionAction { 9 | STOP("stop"), 10 | KEEP_EXISTING("keep_existing"), 11 | KEEP_BUMPED("keep_bumped"); 12 | 13 | public final String value; 14 | 15 | JobCollisionAction(final String value) { 16 | this.value = value; 17 | } 18 | 19 | public static String stringValues(final String delimiter) { 20 | return Arrays.stream(JobCollisionAction.values()) 21 | .map(variant -> variant.value) 22 | .collect(Collectors.joining(delimiter)); 23 | } 24 | 25 | public static Result parse(final String value) { 26 | try { 27 | return Result.ok(JobCollisionAction.valueOf(value.toUpperCase())); 28 | } catch (IllegalArgumentException e) { 29 | return Result.err("Invalid job collision action: " + value + ". Valid options are: " + stringValues(", ")); 30 | } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/utils/matrix/cell/UrlCell.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.core.utils.matrix.cell; 2 | 3 | import java.util.Objects; 4 | import java.util.Optional; 5 | 6 | public class UrlCell extends TitleCell { 7 | private final String url; 8 | 9 | public UrlCell(final String title) { 10 | super(title); 11 | url = null; 12 | } 13 | 14 | public UrlCell(final String title, final String url) { 15 | super(title); 16 | this.url = url; 17 | } 18 | 19 | public Optional getUrl() { 20 | return Optional.ofNullable(url); 21 | } 22 | 23 | @Override 24 | public boolean equals(Object o) { 25 | if (this == o) return true; 26 | if (!(o instanceof UrlCell)) return false; 27 | if (!super.equals(o)) return false; 28 | UrlCell urlCell = (UrlCell) o; 29 | return Objects.equals(url, urlCell.url); 30 | } 31 | 32 | @Override 33 | public int hashCode() { 34 | return Objects.hash(super.hashCode(), url); 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return getUrl().orElse(getTitle()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /webapp/src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { useObserver } from "mobx-react" 3 | 4 | import { AppBar, Tabs, Tab, Toolbar } from "@material-ui/core" 5 | import useStores from "../hooks/useStores" 6 | 7 | const Header: React.FC = () => { 8 | const { configStore, viewStore } = useStores() 9 | 10 | return useObserver(() => { 11 | const { selectedConfigGroupId } = configStore 12 | const { goToConfigList } = viewStore 13 | return ( 14 | 15 | 16 | 17 | {configStore.configGroups.map(({ id }, index) => ( 18 | goToConfigList(id)} 20 | key={index} 21 | label={id} 22 | value={id} 23 | /> 24 | ))} 25 | 26 | 27 | 28 | 29 | ) 30 | }) 31 | } 32 | 33 | export default Header 34 | -------------------------------------------------------------------------------- /webapp/src/components/formComponents/Checkbox.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { FormControl, FormControlLabel, Checkbox as CheckboxMaterial } from "@material-ui/core"; 3 | 4 | type CheckboxPropsRequired = { 5 | label: string 6 | } 7 | 8 | type CheckboxPropsOptional = { 9 | onChange: (value: boolean) => void 10 | value: boolean 11 | } 12 | 13 | type CheckboxProps = CheckboxPropsRequired & CheckboxPropsOptional 14 | 15 | class Checkbox extends React.PureComponent { 16 | 17 | static defaultProps: CheckboxPropsOptional = { 18 | onChange: _ => null, 19 | value: false 20 | } 21 | 22 | onChange = (event: React.ChangeEvent) => { 23 | this.props.onChange(event.target.checked) 24 | } 25 | 26 | render() { 27 | const { label, value } = this.props 28 | return ( 29 | 30 | } 35 | label={label} /> 36 | 37 | ) 38 | } 39 | } 40 | 41 | export default Checkbox 42 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/ManagementUtils.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager; 2 | 3 | import org.fakekoji.storage.Storage; 4 | 5 | import java.util.function.BiConsumer; 6 | import java.util.function.Consumer; 7 | 8 | public class ManagementUtils { 9 | 10 | public static void checkID(String id, Storage storage) throws ManagementException { 11 | checkID(id, storage, true); 12 | } 13 | 14 | public static void checkID(String id, Storage storage, boolean shouldExist) throws ManagementException { 15 | if (storage.contains(id) != shouldExist) { 16 | throw new ManagementException("Resource with ID " + id + 17 | (shouldExist ? " does not exist" : " already exists") + '!' 18 | ); 19 | } 20 | } 21 | 22 | public static Consumer managementConsumerWrapper(ManagementConsumer consumer) { 23 | return i -> { 24 | try { 25 | consumer.accept(i); 26 | } catch (ManagementException e) { 27 | throw new RuntimeException(e); 28 | } 29 | }; 30 | } 31 | 32 | public interface ManagementConsumer { 33 | 34 | void accept(T t) throws ManagementException; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcresponse/FakeBuildList.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcresponse; 2 | 3 | import hudson.plugins.scm.koji.model.Build; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.LinkedList; 8 | import java.util.List; 9 | import java.util.function.Supplier; 10 | import java.util.stream.Collectors; 11 | import java.util.stream.Stream; 12 | 13 | public class FakeBuildList implements XmlRpcResponse> { 14 | 15 | private final List buildList; 16 | 17 | public FakeBuildList(List buildList) { 18 | this.buildList = buildList; 19 | } 20 | 21 | @Override 22 | public Object toObject() { 23 | return buildList; 24 | } 25 | 26 | @Override 27 | public List getValue() { 28 | return buildList; 29 | } 30 | 31 | @SuppressWarnings("unchecked") 32 | public static FakeBuildList create(Object object) { 33 | final Object[] array = (Object[]) object; 34 | final List builds = Stream.of(array) 35 | .filter(obj -> obj instanceof Build) 36 | .map(obj -> (Build) obj) 37 | .collect(Collectors.toList()); 38 | return new FakeBuildList(builds); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/model/JobConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.model; 2 | 3 | import org.fakekoji.Utils; 4 | 5 | import java.util.Collections; 6 | import java.util.Objects; 7 | import java.util.Set; 8 | 9 | public class JobConfiguration { 10 | 11 | private final Set platforms; 12 | 13 | public JobConfiguration() { 14 | platforms = Collections.emptySet(); 15 | } 16 | 17 | public JobConfiguration(Set platforms) { 18 | this.platforms = platforms != null ? platforms : Collections.emptySet(); 19 | } 20 | 21 | public Set getPlatforms() { 22 | return platforms; 23 | } 24 | 25 | @Override 26 | public boolean equals(Object o) { 27 | if (this == o) return true; 28 | if (!(o instanceof JobConfiguration)) return false; 29 | JobConfiguration that = (JobConfiguration) o; 30 | return Utils.areEqual(platforms, that.platforms); 31 | } 32 | 33 | @Override 34 | public int hashCode() { 35 | return Objects.hash(platforms); 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "JobConfiguration{" + 41 | "platforms=" + platforms + 42 | '}'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/model/Product.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.model; 2 | 3 | import java.util.Objects; 4 | 5 | public class Product { 6 | 7 | private final String jdk; 8 | private final String packageName; 9 | 10 | public Product() { 11 | jdk = null; 12 | packageName = null; 13 | } 14 | 15 | public Product(String jdk, String packageName) { 16 | this.jdk = jdk; 17 | this.packageName = packageName; 18 | } 19 | 20 | public String getJdk() { 21 | return jdk; 22 | } 23 | 24 | public String getPackageName() { 25 | return packageName; 26 | } 27 | 28 | @Override 29 | public boolean equals(Object o) { 30 | if (this == o) return true; 31 | if (!(o instanceof Product)) return false; 32 | Product product = (Product) o; 33 | return Objects.equals(jdk, product.jdk) && 34 | Objects.equals(packageName, product.packageName); 35 | } 36 | 37 | @Override 38 | public int hashCode() { 39 | return Objects.hash(jdk, packageName); 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return "Product{" + 45 | "jdk='" + jdk + '\'' + 46 | ", packageName='" + packageName + '\'' + 47 | '}'; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/model/TestJobConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.model; 2 | 3 | import org.fakekoji.Utils; 4 | 5 | import java.util.Collections; 6 | import java.util.Objects; 7 | import java.util.Set; 8 | 9 | public class TestJobConfiguration { 10 | 11 | private final Set platforms; 12 | 13 | public TestJobConfiguration() { 14 | platforms = Collections.emptySet(); 15 | } 16 | 17 | public TestJobConfiguration(Set platforms) { 18 | this.platforms = platforms != null ? platforms : Collections.emptySet(); 19 | } 20 | 21 | public Set getPlatforms() { 22 | return platforms; 23 | } 24 | 25 | @Override 26 | public boolean equals(Object o) { 27 | if (this == o) return true; 28 | if (!(o instanceof TestJobConfiguration)) return false; 29 | TestJobConfiguration that = (TestJobConfiguration) o; 30 | return Utils.areEqual(platforms, that.platforms); 31 | } 32 | 33 | @Override 34 | public int hashCode() { 35 | return Objects.hash(platforms); 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "TestJobConfiguration{" + 41 | "platforms=" + platforms + 42 | '}'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /webapp/src/components/formComponents/TextArea.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { FormControl, FormLabel, TextareaAutosize } from "@material-ui/core"; 3 | 4 | type TextAreaPropsOptional = { 5 | onChange: (value: string) => void 6 | placeholder: string 7 | value: string 8 | } 9 | 10 | type TextAreaPropsRequired = { 11 | label: string 12 | } 13 | 14 | type TextAreaProps = TextAreaPropsRequired & TextAreaPropsOptional 15 | 16 | class TextArea extends React.PureComponent { 17 | 18 | static defaultProps: TextAreaPropsOptional = { 19 | onChange: _ => { }, 20 | placeholder: "", 21 | value: "" 22 | } 23 | 24 | onChange = (event: React.ChangeEvent) => { 25 | this.props.onChange(event.target.value) 26 | } 27 | 28 | render() { 29 | const { label, placeholder, value } = this.props 30 | return ( 31 | 32 | 33 | 34 | 35 | 39 | 40 | ) 41 | } 42 | } 43 | 44 | export default TextArea; 45 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/functional/Result.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.functional; 2 | 3 | import java.util.function.Function; 4 | 5 | public class Result { 6 | private final V value; 7 | private final E error; 8 | 9 | private Result(V value, E error) { 10 | this.value = value; 11 | this.error = error; 12 | } 13 | 14 | public static Result ok(T value) { 15 | return new Result<>(value, null); 16 | } 17 | 18 | public static Result err(U error) { 19 | return new Result<>(null, error); 20 | } 21 | 22 | public Result flatMap(Function> mapper) { 23 | if (isError()) { 24 | return Result.err(error); 25 | } 26 | return mapper.apply(value); 27 | } 28 | 29 | public Result map(Function mapper) { 30 | if (isError()) { 31 | return Result.err(error); 32 | } 33 | return Result.ok(mapper.apply(value)); 34 | } 35 | 36 | public boolean isOk() { 37 | return !isError(); 38 | } 39 | 40 | public boolean isError() { 41 | return this.error != null; 42 | } 43 | 44 | public V getValue() { 45 | return this.value; 46 | } 47 | 48 | public E getError() { 49 | return this.error; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /webapp/src/components/formComponents/FormList.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { useObserver } from "mobx-react" 3 | import { FormControl, FormLabel, IconButton } from "@material-ui/core" 4 | import { Add, } from "@material-ui/icons" 5 | import DeleteButton from "../DeleteButton" 6 | 7 | interface FormListProps { 8 | data: any[] 9 | label: string 10 | onAdd: () => any 11 | renderItem: (item: any, index: number) => React.ReactNode 12 | } 13 | 14 | const FormList: React.FC = props => { 15 | return useObserver(() => { 16 | const { data, label, onAdd, renderItem } = props 17 | return ( 18 |
19 | 20 | {label} 21 | {data.map((item, index) => ( 22 |
23 | {renderItem(item, index)} 24 | data.splice(index, 1)} /> 25 |
26 | ))} 27 |
28 | data.push(onAdd())}> 29 | 30 | 31 |
32 | ) 33 | }) 34 | } 35 | 36 | export default FormList 37 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/utils/matrix/cell/CellGroup.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.core.utils.matrix.cell; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Objects; 6 | 7 | public class CellGroup implements Cell { 8 | 9 | private final List cells; 10 | 11 | public CellGroup() { 12 | cells = new ArrayList<>(); 13 | } 14 | 15 | public CellGroup(final List cells) { 16 | this.cells = cells; 17 | } 18 | 19 | public void add(final TitleCell cell) { 20 | cells.add(cell); 21 | } 22 | 23 | public boolean isEmpty() { 24 | return cells.isEmpty(); 25 | } 26 | 27 | @Override 28 | public int getSpan() { 29 | return cells.stream().map(Cell::getSpan).reduce(0, Integer::sum); 30 | } 31 | 32 | public int size() { 33 | return cells.size(); 34 | } 35 | 36 | public List getCells() { 37 | return cells; 38 | } 39 | 40 | @Override 41 | public boolean equals(Object o) { 42 | if (this == o) return true; 43 | if (!(o instanceof CellGroup)) return false; 44 | CellGroup cellGroup = (CellGroup) o; 45 | return Objects.equals(cells, cellGroup.cells); 46 | } 47 | 48 | @Override 49 | public int hashCode() { 50 | return Objects.hash(cells); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /webapp/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Header from "./components/Header" 3 | import ConfigForm from "./components/configForms/ConfigForm" 4 | import ConfirmDialog from "./components/ConfirmDialog" 5 | import ResultDialog from "./components/ResultDialog" 6 | import { useObserver } from "mobx-react" 7 | 8 | import { Grid } from "@material-ui/core" 9 | import useStores from "./hooks/useStores" 10 | import List from "./components/List" 11 | 12 | const App: React.FC = () => { 13 | const { configStore, viewStore } = useStores() 14 | 15 | React.useEffect(() => { 16 | configStore.fetchJenkinsUrl() 17 | configStore.fetchConfigs() 18 | }, [configStore]) 19 | 20 | const content = useObserver(() => { 21 | const { currentView } = viewStore 22 | switch (currentView) { 23 | case "form": 24 | return 25 | case "list": 26 | return 27 | } 28 | }) 29 | 30 | return ( 31 | 32 |
33 | 34 | 35 | {content} 36 | 37 | 38 | 39 | 40 | 41 | ) 42 | } 43 | 44 | export default App 45 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/ManagementResult.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager; 2 | 3 | import org.fakekoji.jobmanager.model.JobUpdateResults; 4 | 5 | import java.util.Objects; 6 | 7 | public class ManagementResult { 8 | 9 | public final C config; 10 | public final JobUpdateResults jobUpdateResults; 11 | 12 | public ManagementResult(C config, JobUpdateResults jobUpdateResults) { 13 | this.config = config; 14 | this.jobUpdateResults = jobUpdateResults; 15 | } 16 | 17 | public ManagementResult(C config) { 18 | this.config = config; 19 | this.jobUpdateResults = new JobUpdateResults(); 20 | } 21 | 22 | @Override 23 | public boolean equals(Object o) { 24 | if (this == o) return true; 25 | if (!(o instanceof ManagementResult)) return false; 26 | ManagementResult that = (ManagementResult) o; 27 | return Objects.equals(config, that.config) && 28 | Objects.equals(jobUpdateResults, that.jobUpdateResults); 29 | } 30 | 31 | @Override 32 | public int hashCode() { 33 | return Objects.hash(config, jobUpdateResults); 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "ManagementResult{" + 39 | "config=" + config + 40 | ", jobupdateResults=" + jobUpdateResults + 41 | '}'; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcrequestparams/GetPackageId.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcrequestparams; 2 | 3 | import java.util.Objects; 4 | 5 | import hudson.plugins.scm.koji.Constants; 6 | 7 | public class GetPackageId implements XmlRpcRequestParams { 8 | 9 | private final String packageName; 10 | 11 | public GetPackageId(String packageName) { 12 | this.packageName = packageName; 13 | } 14 | 15 | @Override 16 | public Object[] toXmlRpcParams() { 17 | return new Object[]{packageName}; 18 | } 19 | 20 | @Override 21 | public String getMethodName() { 22 | return Constants.getPackageID; 23 | } 24 | 25 | public String getPackageName() { 26 | return packageName; 27 | } 28 | 29 | public static GetPackageId create(Object object) { 30 | return new GetPackageId((String) object); 31 | } 32 | 33 | @Override 34 | public boolean equals(Object o) { 35 | if (this == o) return true; 36 | if (o == null || getClass() != o.getClass()) return false; 37 | GetPackageId that = (GetPackageId) o; 38 | return Objects.equals(packageName, that.packageName) && 39 | Objects.equals(getMethodName(), that.getMethodName()); 40 | } 41 | 42 | @Override 43 | public int hashCode() { 44 | return Objects.hash(getMethodName(), packageName); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /fake-koji/src/test/resources/org/fakekoji/core/utils/matrix/filtered_matrix: -------------------------------------------------------------------------------- 1 | all projects el7.x86_64.?-build el7.x86_64.?-jtreg-? el7.x86_64.?-tck-? f29.x86_64.?-build f29.x86_64.?-tck-? all projects 2 | el7.x86_64.?-jdk8-projectName-?0 0 0 0 0 el7.x86_64.?-jdk8-projectName-? 3 | el7.x86_64.?-jdk8-testProject-?1 1 2 0 2 el7.x86_64.?-jdk8-testProject-? 4 | el7.x86_64.?-jdk8-uName-? 1 0 4 0 0 el7.x86_64.?-jdk8-uName-? 5 | f29.x86_64.?-jdk8-uName-? 0 0 0 1 4 f29.x86_64.?-jdk8-uName-? 6 | 16/2904 el7.x86_64.?-build el7.x86_64.?-jtreg-? el7.x86_64.?-tck-? f29.x86_64.?-build f29.x86_64.?-tck-? 16/2904 -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcrequestparams/XmlRpcRequestParams.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcrequestparams; 2 | 3 | import org.fakekoji.xmlrpc.server.expensiveobjectscache.CachableRequest; 4 | 5 | import java.io.Serializable; 6 | import java.util.Arrays; 7 | import java.util.stream.Collectors; 8 | 9 | 10 | public interface XmlRpcRequestParams extends Serializable, CachableRequest { 11 | 12 | /** 13 | * This method converts POJO to a map of objects with additional parameters based on XML-RPC method it is used for. 14 | * This method is used by XML-RPC client for sending XML-RPC requests. 15 | * 16 | * @return map of objects as Object 17 | * @see ListRPMs 18 | * @see GetPackageId 19 | */ 20 | Object[] toXmlRpcParams(); 21 | 22 | /** 23 | * This method returns name of the XML-RPC method that this class represents parameters of. 24 | * 25 | * @return XML-RPC method name 26 | */ 27 | String getMethodName(); 28 | 29 | public static String toNiceString(XmlRpcRequestParams o) { 30 | if (o == null) { 31 | return "null"; 32 | } 33 | if (o.toXmlRpcParams() == null || o.toXmlRpcParams().length == 0) { 34 | return o.getMethodName() + "()"; 35 | } 36 | return o.getMethodName()+"("+ Arrays.stream(o.toXmlRpcParams()).map(Object::toString).collect(Collectors.joining(","))+")"; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /webapp/src/components/formComponents/RPMLimitationForm.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Grid } from "@material-ui/core" 3 | import { useObserver } from "mobx-react" 4 | 5 | import { RPMLimitation } from "../../stores/model" 6 | import TextInput from "./TextInput" 7 | 8 | interface Props { 9 | rpmLimitation: RPMLimitation 10 | } 11 | 12 | const RPMLimitationForm: React.FunctionComponent = ({ rpmLimitation }) => { 13 | 14 | const onRPMLimitationBlacklistChange = (value: string) => { 15 | rpmLimitation.blacklist = value.split(" ") 16 | } 17 | 18 | const onRPMLimitationWhitelistChange = (value: string) => { 19 | rpmLimitation.whitelist = value.split(" ") 20 | } 21 | 22 | return useObserver(() => { 23 | return ( 24 | 25 | 26 | 30 | 34 | 35 | 36 | 37 | ) 38 | }) 39 | } 40 | 41 | export default RPMLimitationForm 42 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/java/hudson/plugins/scm/koji/LoggerHelp.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package hudson.plugins.scm.koji; 23 | 24 | public interface LoggerHelp{ 25 | 26 | public void log(String s); 27 | 28 | public void log(String s, Object o); 29 | 30 | public void log(String s, Object... o); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /webapp/src/components/formComponents/TextInput.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { useObserver } from "mobx-react" 3 | import { TextField } from "@material-ui/core" 4 | import { BasicValidation } from "../../utils/validators" 5 | import { TextFieldProps } from "@material-ui/core/TextField" 6 | 7 | type TextInputPropsRequired = { 8 | label: string 9 | } 10 | 11 | type TextInputPropsOptional = { 12 | onChange: (value: string) => void 13 | validation?: BasicValidation 14 | value?: string 15 | } 16 | 17 | type TextInputProps = TextInputPropsRequired & TextInputPropsOptional 18 | 19 | const TextInput: React.FC = props => 20 | useObserver(() => { 21 | const { label, validation, value } = props 22 | 23 | const onChange = (event: React.ChangeEvent) => { 24 | props.onChange(event.target.value) 25 | } 26 | 27 | const errorProps: TextFieldProps = 28 | (validation && 29 | validation !== "ok" && { 30 | error: true, 31 | helperText: validation 32 | }) || 33 | {} 34 | return ( 35 | 43 | ) 44 | }) 45 | 46 | export default TextInput 47 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/model/JobUpdateResult.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.model; 2 | 3 | import java.util.Objects; 4 | 5 | public class JobUpdateResult { 6 | 7 | public final String jobName; 8 | public final boolean success; 9 | public final String message; 10 | 11 | public JobUpdateResult(String jobName, boolean success, String message) { 12 | this.jobName = jobName; 13 | this.success = success; 14 | this.message = message; 15 | } 16 | 17 | public JobUpdateResult(String jobName, boolean success) { 18 | this.jobName = jobName; 19 | this.success = success; 20 | this.message = ""; 21 | } 22 | 23 | @Override 24 | public boolean equals(Object o) { 25 | if (this == o) return true; 26 | if (!(o instanceof JobUpdateResult)) return false; 27 | JobUpdateResult that = (JobUpdateResult) o; 28 | return success == that.success && 29 | Objects.equals(jobName, that.jobName) && 30 | Objects.equals(message, that.message); 31 | } 32 | 33 | @Override 34 | public int hashCode() { 35 | return Objects.hash(jobName, success, message); 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "JobUpdateResult{" + 41 | "jobName='" + jobName + '\'' + 42 | ", success=" + success + 43 | ", message='" + message + '\'' + 44 | '}'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/model/TaskConfig.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.model; 2 | 3 | import org.fakekoji.Utils; 4 | 5 | import java.util.Collections; 6 | import java.util.Objects; 7 | import java.util.Set; 8 | 9 | public class TaskConfig { 10 | 11 | private final String id; 12 | private final Set variants; 13 | 14 | public TaskConfig() { 15 | id = null; 16 | variants = Collections.emptySet(); 17 | } 18 | 19 | public TaskConfig(final String id, Set variants) { 20 | this.id = id; 21 | this.variants = variants != null ? variants : Collections.emptySet(); 22 | } 23 | 24 | public String getId() { 25 | return id; 26 | } 27 | 28 | public Set getVariants() { 29 | return variants; 30 | } 31 | 32 | @Override 33 | public boolean equals(Object o) { 34 | if (this == o) return true; 35 | if (!(o instanceof TaskConfig)) return false; 36 | TaskConfig that = (TaskConfig) o; 37 | return Objects.equals(id, that.id) && 38 | Utils.areEqual(variants, that.variants); 39 | } 40 | 41 | @Override 42 | public int hashCode() { 43 | return Objects.hash(id, variants); 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "TaskConfig{" + 49 | "id='" + id + '\'' + 50 | ", variants=" + variants + 51 | '}'; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/utils/matrix/formatter/PlainTextFormatter.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.core.utils.matrix.formatter; 2 | 3 | import org.fakekoji.core.utils.matrix.cell.CellGroup; 4 | import org.fakekoji.core.utils.matrix.cell.TitleCell; 5 | import org.fakekoji.core.utils.matrix.cell.UpperCornerCell; 6 | 7 | public class PlainTextFormatter implements Formatter { 8 | 9 | @Override 10 | public String upperCorner(final UpperCornerCell cell) { 11 | if (cell.projectCells().size() > 1) { 12 | return cell.projectCells().size() + " projects"; 13 | } 14 | return cell.projectCells().get(0).getTitle(); 15 | } 16 | 17 | @Override 18 | public String lowerCorner(int found, int all, int span) { 19 | return found + "/" + all; 20 | } 21 | 22 | @Override 23 | public String rowStart() { 24 | return ""; 25 | } 26 | 27 | @Override 28 | public String rowEnd() { 29 | return "\n"; 30 | } 31 | 32 | @Override 33 | public String tableStart() { 34 | return ""; 35 | } 36 | 37 | @Override 38 | public String tableEnd() { 39 | return ""; 40 | } 41 | 42 | @Override 43 | public String edge(final TitleCell titleCell, final int span) { 44 | return titleCell.getTitle(); 45 | } 46 | 47 | @Override 48 | public String cells(final CellGroup cellGroup, int maxInColumn, final String rowTitle, final String colTitle) { 49 | return "" + cellGroup.size(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/JobUpdater.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager; 2 | 3 | import org.fakekoji.functional.Tuple; 4 | import org.fakekoji.jobmanager.model.Job; 5 | import org.fakekoji.jobmanager.model.JobBump; 6 | import org.fakekoji.jobmanager.model.JobCollisionAction; 7 | import org.fakekoji.jobmanager.model.JobUpdateResults; 8 | import org.fakekoji.jobmanager.model.Project; 9 | import org.fakekoji.model.Platform; 10 | import org.fakekoji.model.Task; 11 | import org.fakekoji.storage.StorageException; 12 | 13 | import java.util.Set; 14 | import java.util.function.Function; 15 | 16 | public interface JobUpdater { 17 | 18 | JobUpdateResults update(Project oldProject, Project newProject) throws StorageException, ManagementException; 19 | 20 | JobUpdateResults regenerate(Project project, String whitelist) throws StorageException, ManagementException; 21 | 22 | JobUpdateResults regenerateAll( 23 | String projectId, 24 | Manager projectManager, 25 | String whitelist 26 | ) throws StorageException, ManagementException; 27 | 28 | JobUpdateResults update(Platform platform) throws StorageException; 29 | 30 | JobUpdateResults update(Task task) throws StorageException; 31 | 32 | Function, JobBump> getCollisionCheck(); 33 | 34 | Set> findCollisions(final Set> jobTuples); 35 | 36 | JobUpdateResults bump(final Set jobTuple, final JobCollisionAction action); 37 | } 38 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/KojiSCM/help-KojiSCMConfig_requireWorkspace.html: -------------------------------------------------------------------------------- 1 |
2 |

If checked, then KojiSCM plugin requires workspace for pooling.

3 |
    4 |
  • By default not-selected
  • 5 |
  • If KojiSCM requires workspace, then the single exact job can not be run in parallel
  • 6 |
  • If KojiSCM don't requires workspace, then the single exact job can be run in parallel
  • 7 |
  • if you unselect it (so it don't require workspace), you may run the same job in parallel
  • 8 |
  • In that case, be sure, that next pooling is invoked after the checkout is finished, otherwise you end with same build in queue
  • 9 |
  • General usecase is:
  • 10 |
      11 |
    • some long job is running, but otherwise the host is bored
    • 12 |
    • everything else is done except next this job
    • 13 |
    • in desired project select "Execute concurrent builds if necessary"
    • 14 |
    • unselect this
    • 15 |
    • schedule/let schedule another job and wait until it is in execution (in parallel)
    • 16 |
    • select this
    • 17 |
    • in desired project unselect "Execute concurrent builds if necessary"
    • 18 |
    • after its checkout is done, verify processed.txt in job's folder
    • 19 |
    20 |
  • this option unselected is not exactly well tested
  • 21 |
22 |
-------------------------------------------------------------------------------- /koji-scm-lib/src/test/java/hudson/plugins/scm/koji/LocalDateTimeWithDateTimeFormatterTest.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.scm.koji; 2 | 3 | import org.junit.Test; 4 | 5 | import java.time.LocalDateTime; 6 | 7 | import static org.junit.Assert.*; 8 | 9 | public class LocalDateTimeWithDateTimeFormatterTest { 10 | @Test 11 | public void testDTFOptionalWithMicros() { 12 | assertEquals(LocalDateTime.of(2018, 12, 31, 12, 34, 56, 123456000), 13 | LocalDateTime.parse("2018-12-31 12:34:56.123456", Constants.DTF)); 14 | } 15 | 16 | @Test 17 | public void testDTFOptionalWithoutMicros() { 18 | // Brew started sending datetime without microseconds for some builds and this format caused an issue with our 19 | // DateTimeFormatter. It is fixed now with optional microseconds. 20 | assertEquals(LocalDateTime.of(2018, 12, 31, 12, 34, 56), 21 | LocalDateTime.parse("2018-12-31 12:34:56", Constants.DTF)); 22 | } 23 | 24 | @Test 25 | public void testDTFOptionalToStringWithoutMicros() { 26 | LocalDateTime expectedTime = LocalDateTime.of(2018, 12, 31, 12, 34, 56); 27 | 28 | assertEquals("2018-12-31 12:34:56.0", Constants.DTF.format(expectedTime)); 29 | } 30 | 31 | @Test 32 | public void testDTFOptionalToStringWithMicros() { 33 | LocalDateTime expectedTime = LocalDateTime.of(2018, 12, 31, 12, 34, 56, 123456000); 34 | 35 | assertEquals("2018-12-31 12:34:56.123456", Constants.DTF.format(expectedTime)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /webapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "otool", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@babel/core": "^7.17.2", 7 | "@babel/plugin-syntax-flow": "^7.16.7", 8 | "@babel/plugin-transform-react-jsx": "^7.16.7", 9 | "@material-ui/core": "^4.12.3", 10 | "@material-ui/icons": "^4.11.2", 11 | "@types/history": "^5.0.0", 12 | "@types/jest": "27.4.0", 13 | "@types/node": "17.0.16", 14 | "@types/react": "17.0.39", 15 | "@types/react-dom": "17.0.11", 16 | "acorn": "^8.7.0", 17 | "autoprefixer": "^10.4.2", 18 | "browserslist": "^4.19.1", 19 | "history": "^5.2.0", 20 | "kind-of": "^6.0.3", 21 | "minimist": "^1.2.6", 22 | "mobx": "6.3.13", 23 | "mobx-react": "7.2.1", 24 | "path-to-regexp": "^6.3.0", 25 | "postcss": "^8.4.31", 26 | "react": "17.0.2", 27 | "react-dom": "17.0.2", 28 | "react-scripts": "5.0.0", 29 | "serialize-javascript": "^6.0.0", 30 | "typescript": "4.5.5" 31 | }, 32 | "scripts": { 33 | "start": "react-scripts start", 34 | "build": "react-scripts build", 35 | "test": "react-scripts test", 36 | "eject": "react-scripts eject" 37 | }, 38 | "eslintConfig": { 39 | "extends": "react-app" 40 | }, 41 | "browserslist": { 42 | "production": [ 43 | ">0.2%", 44 | "not dead", 45 | "not op_mini all" 46 | ], 47 | "development": [ 48 | "last 1 chrome version", 49 | "last 1 firefox version", 50 | "last 1 safari version" 51 | ] 52 | }, 53 | "devDependencies": {} 54 | } 55 | -------------------------------------------------------------------------------- /webapp/src/components/ConfirmDialog.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Dialog, DialogTitle, DialogActions, Button } from "@material-ui/core" 3 | import { useObserver } from "mobx-react" 4 | 5 | import useStores from "../hooks/useStores" 6 | 7 | interface ConfirmDialogProps {} 8 | 9 | const ConfirmDialog: React.FC = () => { 10 | const { viewStore } = useStores() 11 | const yesButton = React.useRef(null) 12 | 13 | const onEnter = React.useCallback(() => { 14 | if (!viewStore.dialog.open) { 15 | return 16 | } 17 | if (!yesButton.current) { 18 | return 19 | } 20 | yesButton.current.focus() 21 | }, [viewStore.dialog.open]) 22 | 23 | return useObserver(() => { 24 | const { closeDialog, dialog } = viewStore 25 | const onYesClick = () => { 26 | closeDialog() 27 | dialog.action() 28 | } 29 | const onNoClick = () => { 30 | closeDialog() 31 | } 32 | return ( 33 | 34 | {dialog.label} 35 | 36 | 39 | 40 | 41 | 42 | ) 43 | }) 44 | } 45 | 46 | export default ConfirmDialog 47 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/model/BuildPlatformConfig.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.model; 2 | 3 | import org.fakekoji.Utils; 4 | 5 | import java.util.Collections; 6 | import java.util.List; 7 | import java.util.Objects; 8 | import java.util.Set; 9 | 10 | public class BuildPlatformConfig { 11 | 12 | private final String id; 13 | private final Set variants; 14 | 15 | public BuildPlatformConfig() { 16 | id = null; 17 | variants = Collections.emptySet(); 18 | } 19 | 20 | public BuildPlatformConfig(String id, Set variants) { 21 | this.id = id; 22 | this.variants = variants != null ? variants : Collections.emptySet(); 23 | } 24 | 25 | public String getId() { 26 | return id; 27 | } 28 | 29 | public Set getVariants() { 30 | return variants; 31 | } 32 | 33 | @Override 34 | public boolean equals(Object o) { 35 | if (this == o) return true; 36 | if (!(o instanceof BuildPlatformConfig)) return false; 37 | BuildPlatformConfig that = (BuildPlatformConfig) o; 38 | return Objects.equals(id, that.id) && 39 | Utils.areEqual(variants, that.variants); 40 | } 41 | 42 | @Override 43 | public int hashCode() { 44 | return Objects.hash(id, variants); 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return "BuildPlatformConfig{" + 50 | "id='" + id + '\'' + 51 | ", variants=" + variants + 52 | '}'; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/utils/DirFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2015 user. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.fakekoji.core.utils; 25 | 26 | import java.io.File; 27 | import java.io.FileFilter; 28 | 29 | public class DirFilter implements FileFilter { 30 | 31 | public DirFilter() { 32 | } 33 | 34 | @Override 35 | public boolean accept(File pathname) { 36 | return pathname.isDirectory(); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/utils/FileFileFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2015 user. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.fakekoji.core.utils; 25 | 26 | import java.io.File; 27 | import java.io.FileFilter; 28 | 29 | public class FileFileFilter implements FileFilter { 30 | 31 | public FileFileFilter() { 32 | } 33 | 34 | @Override 35 | public boolean accept(File pathname) { 36 | return !pathname.isDirectory(); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /koji-scm-lib/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | fake-koji 7 | koji-scm 8 | 2.2-SNAPSHOT 9 | 10 | 11 | koji-scm-lib 12 | jar 13 | 14 | Koji SCM Lib 15 | 16 | 17 | 18 | org.apache.xmlrpc 19 | xmlrpc-client 20 | 21 | 22 | org.slf4j 23 | slf4j-jdk14 24 | 1.7.33 25 | 26 | 27 | com.github.spotbugs 28 | spotbugs-annotations 29 | 4.5.3 30 | 31 | 32 | jakarta.xml.bind 33 | jakarta.xml.bind-api 34 | 3.0.1 35 | 36 | 37 | com.sun.xml.bind 38 | jaxb-impl 39 | 2.3.3 40 | runtime 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/utils/matrix/TestSpec.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.core.utils.matrix; 2 | 3 | import org.fakekoji.model.Platform; 4 | import org.fakekoji.model.Task; 5 | 6 | import java.util.Collections; 7 | import java.util.List; 8 | 9 | class TestSpec extends Spec { 10 | private final Task task; 11 | 12 | 13 | public TestSpec( 14 | final Platform platform, 15 | final Platform.Provider provider, 16 | final Task task, 17 | final List variants, 18 | final TestEqualityFilter viewFilter 19 | ) { 20 | super(platform, provider, viewFilter, variants); 21 | this.task = task; 22 | } 23 | 24 | public TestSpec( 25 | final Platform platform, 26 | final Platform.Provider provider, 27 | final Task task, 28 | final TestEqualityFilter viewFilter 29 | ) { 30 | super(platform, provider, viewFilter, Collections.emptyList()); 31 | this.task = task; 32 | } 33 | 34 | public Task getTask() { 35 | return task; 36 | } 37 | 38 | private TestEqualityFilter getViewFilter() { 39 | return (TestEqualityFilter) viewFilter; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | String tsk = task.getId(); 45 | if (!getViewFilter().suite) { 46 | tsk = "?"; 47 | } 48 | return getPlatformString()+ 49 | "-" + tsk + getVariantsString(); 50 | } 51 | 52 | public boolean matchSuite(String id){ 53 | return !getViewFilter().suite || task.getId().equals(id); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcrequestparams/GetBuildDetail.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcrequestparams; 2 | 3 | import java.util.Objects; 4 | 5 | import hudson.plugins.scm.koji.Constants; 6 | 7 | public class GetBuildDetail implements XmlRpcRequestParams { 8 | 9 | private final String nvr; 10 | public final String n; 11 | public final String v; 12 | public final String r; 13 | 14 | public GetBuildDetail(String n, String v, String r) { 15 | this.nvr = n + "-" + v + "-" + r; 16 | this.n = n; 17 | this.v = v; 18 | this.r = r; 19 | } 20 | 21 | @Override 22 | public Object[] toXmlRpcParams() { 23 | return new Object[]{this}; 24 | } 25 | 26 | @Override 27 | public boolean equals(Object o) { 28 | if (this == o) return true; 29 | if (o == null || getClass() != o.getClass()) return false; 30 | GetBuildDetail that = (GetBuildDetail) o; 31 | return Objects.equals(n, that.n) && 32 | Objects.equals(v, that.v) && 33 | Objects.equals(r, that.r) && 34 | Objects.equals(getMethodName(), that.getMethodName()); 35 | } 36 | 37 | @Override 38 | public int hashCode() { 39 | return Objects.hash(getMethodName(), n, v, r); 40 | } 41 | 42 | @Override 43 | public String getMethodName() { 44 | return Constants.getBuildDetail; 45 | } 46 | 47 | public String getNvr() { 48 | return nvr; 49 | } 50 | 51 | public static GetBuildDetail create(Object object) { 52 | return (GetBuildDetail) object; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcresponse/TagSet.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcresponse; 2 | 3 | import hudson.plugins.scm.koji.Constants; 4 | 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.HashSet; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.Set; 11 | 12 | import static org.fakekoji.xmlrpc.server.xmlrpcrequestparams.XmlRpcRequestUtils.toMaps; 13 | 14 | public class TagSet implements XmlRpcResponse> { 15 | 16 | private final Set tags; 17 | 18 | public TagSet(Set tags) { 19 | this.tags = tags; 20 | } 21 | 22 | @Override 23 | public Object toObject() { 24 | return parseTags(); 25 | } 26 | 27 | @Override 28 | public Set getValue() { 29 | return tags; 30 | } 31 | 32 | private static Set parseTagMaps(List> maps) { 33 | final Set tags = new HashSet<>(); 34 | for (Map tagMap : maps) { 35 | tags.add((String) tagMap.get(Constants.name)); 36 | } 37 | return tags; 38 | } 39 | 40 | private List> parseTags() { 41 | List> maps = new ArrayList<>(); 42 | for (String tag : tags) { 43 | Map tagMap = new HashMap<>(); 44 | tagMap.put(Constants.name, tag); 45 | maps.add(tagMap); 46 | } 47 | return maps; 48 | } 49 | 50 | public static TagSet create(Object object) { 51 | return new TagSet(parseTagMaps(toMaps(object))); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/api/http/rest/args/BumpArgs.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.api.http.rest.args; 2 | 3 | import org.fakekoji.api.http.rest.OToolError; 4 | import org.fakekoji.api.http.rest.RestUtils; 5 | import org.fakekoji.functional.Result; 6 | import org.fakekoji.jobmanager.model.JobCollisionAction; 7 | 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | import static org.fakekoji.api.http.rest.BumperAPI.EXECUTE; 12 | import static org.fakekoji.api.http.rest.BumperAPI.JOB_COLLISION_ACTION; 13 | 14 | public class BumpArgs { 15 | public final JobCollisionAction action; 16 | public boolean execute; 17 | 18 | public BumpArgs(final JobCollisionAction action, final boolean execute) { 19 | this.action = action; 20 | this.execute = execute; 21 | } 22 | 23 | BumpArgs(final BumpArgs bumpArgs) { 24 | this(bumpArgs.action, bumpArgs.execute); 25 | } 26 | 27 | public static Result parseBumpArgs(final Map> paramsMap) { 28 | final String executeParam = RestUtils.extractParamValue(paramsMap, EXECUTE).orElse("false"); 29 | final boolean execute = Boolean.parseBoolean(executeParam); 30 | final Result actionResult = RestUtils.extractParamValue(paramsMap, JOB_COLLISION_ACTION) 31 | .map(JobCollisionAction::parse) 32 | .orElse(Result.ok(JobCollisionAction.STOP)); 33 | if (actionResult.isError()) { 34 | return Result.err(new OToolError(actionResult.getError(), 400)); 35 | } 36 | return Result.ok(new BumpArgs(actionResult.getValue(), execute)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /webapp/src/components/formComponents/Select.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { 3 | FormControl, 4 | InputLabel, 5 | Select as MaterialSelect, 6 | MenuItem, 7 | FormHelperText 8 | } from "@material-ui/core" 9 | import { BasicValidation } from "../../utils/validators" 10 | 11 | type SelectPropsRequired = { 12 | options: string[] 13 | } 14 | 15 | type SelectPropsOptional = { 16 | label?: string 17 | onChange: (value: string) => void 18 | validation?: BasicValidation 19 | value?: string 20 | } 21 | 22 | type SelectProps = SelectPropsRequired & SelectPropsOptional 23 | 24 | const Select: React.FC = props => { 25 | const { label, options, validation, value } = props 26 | 27 | const onChange = ( 28 | event: React.ChangeEvent<{ name?: string | undefined; value: unknown }> 29 | ) => { 30 | props.onChange(event.target.value as string) 31 | } 32 | 33 | const isError = validation && validation !== "ok" 34 | 35 | return ( 36 | 37 | {label && {label}} 38 | 41 | None 42 | {options.map(option => ( 43 | 44 | {option} 45 | 46 | ))} 47 | 48 | {isError && {validation}} 49 | 50 | ) 51 | } 52 | 53 | export default Select 54 | -------------------------------------------------------------------------------- /webapp/src/styles/Forms.css: -------------------------------------------------------------------------------- 1 | fieldset { 2 | border: none; 3 | } 4 | 5 | form { 6 | padding: 12px; 7 | } 8 | 9 | label { 10 | padding: 12px 12px 12px 0; 11 | display: inline-block; 12 | } 13 | 14 | input[type=text], select, textarea { 15 | width: 100%; 16 | padding: 12px; 17 | border: 1px solid #ccc; 18 | border-radius: 4px; 19 | resize: vertical; 20 | } 21 | 22 | .dropdown { 23 | display: inline-block; 24 | position: relative; 25 | } 26 | 27 | .dropdown:hover:hover .dropdown-button { 28 | background-color: #ddd; 29 | } 30 | 31 | .dropdown:hover .dropdown-content { 32 | display: block; 33 | } 34 | 35 | .dropdown-button { 36 | background-color: #ccc; 37 | border: none; 38 | color: #000; 39 | cursor: pointer; 40 | font-size: 16px; 41 | padding: 16px; 42 | } 43 | 44 | .dropdown-content { 45 | background-color: #ccc; 46 | box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); 47 | display: none; 48 | min-width: 160px; 49 | position: absolute; 50 | z-index: 1; 51 | } 52 | 53 | .dropdown-content span { 54 | color: black; 55 | cursor: pointer; 56 | display: block; 57 | padding: 12px 16px; 58 | text-decoration: none; 59 | } 60 | 61 | .dropdown-content span:hover { 62 | background-color: #f1f1f1; 63 | } 64 | 65 | .field-container { 66 | display: grid; 67 | grid-template-columns: 1fr 3fr; 68 | } 69 | 70 | .label-container { 71 | margin-top: 6px; 72 | } 73 | 74 | .value-container { 75 | margin-top: 6px; 76 | } 77 | 78 | .error-container { 79 | background-color: #e33021; 80 | color: #fff; 81 | display: grid; 82 | grid-template-columns: 3fr 1fr; 83 | padding: 10px; 84 | } 85 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/bumpers/BumpResult.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.bumpers; 2 | 3 | import org.fakekoji.jobmanager.BuildDirUpdater; 4 | import org.fakekoji.jobmanager.model.JobUpdateResults; 5 | 6 | import java.util.Optional; 7 | 8 | public class BumpResult { 9 | private final JobUpdateResults jobResults; 10 | private final BuildDirUpdater.BuildUpdateSummary buildUpdateSummary; 11 | private final String message; 12 | 13 | public BumpResult( 14 | final JobUpdateResults jobResults, 15 | final BuildDirUpdater.BuildUpdateSummary buildUpdateSummary, 16 | final String message 17 | ) { 18 | this.jobResults = jobResults; 19 | this.buildUpdateSummary = buildUpdateSummary; 20 | this.message = message == null ? "" : message; 21 | } 22 | 23 | public BumpResult(JobUpdateResults jobResults) { 24 | this(jobResults, null, null); 25 | } 26 | 27 | public BumpResult( 28 | final JobUpdateResults jobResults, 29 | final BuildDirUpdater.BuildUpdateSummary buildUpdateSummary 30 | ) { 31 | this(jobResults, buildUpdateSummary, null); 32 | } 33 | 34 | public BumpResult( 35 | final JobUpdateResults jobResults, 36 | final String message 37 | ) { 38 | this(jobResults, null, message); 39 | } 40 | 41 | 42 | public JobUpdateResults getJobResults() { 43 | return jobResults; 44 | } 45 | 46 | public Optional getBuildUpdateSummary() { 47 | return Optional.ofNullable(buildUpdateSummary); 48 | } 49 | 50 | public String getMessage() { 51 | return message; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcresponse/ArchiveList.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcresponse; 2 | 3 | import hudson.plugins.scm.koji.Constants; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import static org.fakekoji.xmlrpc.server.xmlrpcrequestparams.XmlRpcRequestUtils.toMaps; 11 | 12 | public class ArchiveList implements XmlRpcResponse> { 13 | 14 | private final List archives; 15 | 16 | public ArchiveList(List archives) { 17 | this.archives = archives; 18 | } 19 | 20 | @Override 21 | public Object toObject() { 22 | /* 23 | Normally, it should return array of maps (as array of objects), 24 | but it is not implemented in fake-koji so I return empty array 25 | */ 26 | return new Object[]{}; 27 | } 28 | 29 | @Override 30 | public List getValue() { 31 | return archives; 32 | } 33 | 34 | private static List parseArchiveMaps(List> maps) { 35 | if (maps == null) { 36 | return Collections.emptyList(); 37 | } 38 | final List archives = new ArrayList<>(maps.size()); 39 | for (Map map : maps) { 40 | archives.add(parseArchiveMap(map)); 41 | } 42 | return archives; 43 | } 44 | 45 | private static String parseArchiveMap(Map map) { 46 | return (String) map.get(Constants.filename); 47 | } 48 | 49 | public static ArchiveList create(Object object) { 50 | return new ArchiveList(parseArchiveMaps(toMaps(object))); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/views/VersionlessPlatform.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.views; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.Objects; 6 | 7 | public class VersionlessPlatform implements CharSequence, Comparable { 8 | private final String os; 9 | private final String arch; 10 | 11 | @Override 12 | public boolean equals(Object o) { 13 | if (this == o) return true; 14 | if (o == null || getClass() != o.getClass()) return false; 15 | VersionlessPlatform that = (VersionlessPlatform) o; 16 | return Objects.equals(os, that.os) && 17 | Objects.equals(arch, that.arch); 18 | } 19 | 20 | @Override 21 | public int hashCode() { 22 | return Objects.hash(os, arch); 23 | } 24 | 25 | public VersionlessPlatform(String os, String arch) { 26 | this.os = os; 27 | this.arch = arch; 28 | } 29 | 30 | public String getOs() { 31 | return os; 32 | } 33 | 34 | public String getArch() { 35 | return arch; 36 | } 37 | 38 | public String getId() { 39 | return os + JenkinsViewTemplateBuilderFactory.getMinorDelimiter() + arch; 40 | } 41 | 42 | @Override 43 | public int length() { 44 | return getId().length(); 45 | } 46 | 47 | @Override 48 | public char charAt(int index) { 49 | return getId().charAt(index); 50 | } 51 | 52 | @Override 53 | public CharSequence subSequence(int start, int end) { 54 | return getId().subSequence(start, end); 55 | } 56 | 57 | @Override 58 | public int compareTo(@NotNull VersionlessPlatform o) { 59 | return getId().compareTo(o.getId()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/model/JDKVersion.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.model; 2 | 3 | import java.util.List; 4 | import java.util.Objects; 5 | 6 | public class JDKVersion { 7 | 8 | private final String id; 9 | private final String label; 10 | private final String version; 11 | private final List packageNames; 12 | 13 | public JDKVersion() { 14 | id = null; 15 | label = null; 16 | version = null; 17 | packageNames = null; 18 | } 19 | 20 | public JDKVersion( 21 | String id, 22 | String label, 23 | String version, 24 | List packageNames 25 | ) { 26 | this.id = id; 27 | this.label = label; 28 | this.version = version; 29 | this.packageNames = packageNames; 30 | } 31 | 32 | public String getId() { 33 | return id; 34 | } 35 | 36 | public String getLabel() { 37 | return label; 38 | } 39 | 40 | public String getVersion() { 41 | return version; 42 | } 43 | 44 | public List getPackageNames() { 45 | return packageNames; 46 | } 47 | 48 | @Override 49 | public boolean equals(Object o) { 50 | if (this == o) return true; 51 | if (!(o instanceof JDKVersion)) return false; 52 | JDKVersion product = (JDKVersion) o; 53 | return Objects.equals(id, product.id) && 54 | Objects.equals(label, product.label) && 55 | Objects.equals(version, product.version) && 56 | Objects.equals(packageNames, product.packageNames); 57 | } 58 | 59 | @Override 60 | public int hashCode() { 61 | return Objects.hash(id, label, version, packageNames); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/java/hudson/plugins/scm/koji/client/FakeKojiBuildMatcher.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.scm.koji.client; 2 | 3 | import hudson.plugins.scm.koji.FakeKojiXmlRpcApi; 4 | import hudson.plugins.scm.koji.KojiBuildProvider; 5 | import hudson.plugins.scm.koji.LoggerHelp; 6 | import hudson.plugins.scm.koji.model.Build; 7 | import hudson.plugins.scm.koji.model.BuildProvider; 8 | import org.fakekoji.xmlrpc.server.xmlrpcrequestparams.GetBuildList; 9 | import org.fakekoji.xmlrpc.server.xmlrpcresponse.FakeBuildList; 10 | 11 | import java.util.List; 12 | import java.util.function.Predicate; 13 | 14 | class FakeKojiBuildMatcher extends BuildMatcher { 15 | 16 | private final FakeKojiXmlRpcApi xmlRpcApi; 17 | 18 | public FakeKojiBuildMatcher( 19 | List buildProviders, 20 | Predicate notProcessedNvrPredicate, 21 | int maxBuilds, 22 | FakeKojiXmlRpcApi xmlRpcApi, 23 | LoggerHelp logger 24 | ) { 25 | super(buildProviders, notProcessedNvrPredicate, maxBuilds, logger); 26 | this.xmlRpcApi = xmlRpcApi; 27 | } 28 | 29 | @Override 30 | List getBuilds(BuildProvider buildProvider) { 31 | final GetBuildList getBuildListParams = new GetBuildList( 32 | xmlRpcApi.getProjectName(), 33 | xmlRpcApi.getBuildVariants(), 34 | xmlRpcApi.getBuildPlatform(), 35 | xmlRpcApi.isBuilt() 36 | ); 37 | final FakeBuildList buildList = FakeBuildList.create(execute(buildProvider.getTopUrl(), getBuildListParams)); 38 | return buildList.getValue(); 39 | } 40 | 41 | @Override 42 | Build getBuild(Build build) { 43 | return build; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/core/utils/matrix/BuildSpec.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.core.utils.matrix; 2 | 3 | import org.fakekoji.jobmanager.model.Product; 4 | import org.fakekoji.jobmanager.model.Project; 5 | import org.fakekoji.model.Platform; 6 | 7 | import java.util.List; 8 | 9 | class BuildSpec extends Spec { 10 | 11 | private final String projectName; 12 | private final Product product; 13 | 14 | public BuildSpec( 15 | final Platform platform, 16 | final Platform.Provider provider, 17 | final Project project, 18 | final List variants, 19 | final BuildEqualityFilter viewFilter) { 20 | this(platform, provider, project.getId(), project.getProduct(), variants, viewFilter); 21 | } 22 | 23 | public BuildSpec( 24 | final Platform platform, 25 | final Platform.Provider provider, 26 | final String projectName, 27 | final Product product, 28 | final List variants, 29 | final BuildEqualityFilter viewFilter) { 30 | super(platform, provider, viewFilter, variants); 31 | this.projectName = projectName; 32 | this.product = product; 33 | } 34 | 35 | private BuildEqualityFilter getViewFilter() { 36 | return (BuildEqualityFilter) viewFilter; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | String jdk= product.getJdk(); 42 | if (!getViewFilter().jdk){ 43 | jdk = "?"; 44 | } 45 | 46 | String prj = projectName; 47 | if (!getViewFilter().project){ 48 | prj = "?"; 49 | } 50 | return getPlatformString()+ 51 | "-" + jdk + "-" + prj + 52 | getVariantsString(); 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/model/PlatformConfig.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.model; 2 | 3 | import org.fakekoji.Utils; 4 | 5 | import java.util.Collections; 6 | import java.util.Objects; 7 | import java.util.Set; 8 | 9 | public class PlatformConfig { 10 | 11 | private final String id; 12 | private final Set tasks; 13 | private final String provider; 14 | 15 | public PlatformConfig() { 16 | id = null; 17 | tasks = Collections.emptySet(); 18 | provider = null; 19 | } 20 | 21 | public PlatformConfig(String id, Set tasks, String provider) { 22 | this.id = id; 23 | this.tasks = tasks != null ? tasks : Collections.emptySet(); 24 | this.provider = provider; 25 | } 26 | 27 | public String getId() { 28 | return id; 29 | } 30 | 31 | public Set getTasks() { 32 | return tasks; 33 | } 34 | 35 | public String getProvider() { 36 | return provider; 37 | } 38 | 39 | @Override 40 | public boolean equals(Object o) { 41 | if (this == o) return true; 42 | if (!(o instanceof PlatformConfig)) return false; 43 | PlatformConfig that = (PlatformConfig) o; 44 | return Objects.equals(id, that.id) && 45 | Utils.areEqual(tasks, that.tasks) && 46 | Objects.equals(provider, that.provider); 47 | } 48 | 49 | @Override 50 | public int hashCode() { 51 | return Objects.hash(id, tasks, provider); 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return "PlatformConfig{" + 57 | "id='" + id + '\'' + 58 | ", tasks=" + tasks + 59 | ", provider='" + provider + '\'' + 60 | '}'; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcrequestparams/ListTags.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcrequestparams; 2 | 3 | import hudson.plugins.scm.koji.Constants; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import java.util.Objects; 8 | 9 | import static org.fakekoji.xmlrpc.server.xmlrpcrequestparams.XmlRpcRequestUtils.starStarLabel; 10 | import static org.fakekoji.xmlrpc.server.xmlrpcrequestparams.XmlRpcRequestUtils.toMap; 11 | 12 | public class ListTags implements XmlRpcRequestParams { 13 | 14 | private final Integer buildId; 15 | 16 | public ListTags(Integer buildId) { 17 | this.buildId = buildId; 18 | } 19 | 20 | @Override 21 | public Object[] toXmlRpcParams() { 22 | final Map map = new HashMap<>(); 23 | map.put(Constants.build, buildId); 24 | map.put(starStarLabel, Boolean.TRUE); 25 | return new Object[]{map}; 26 | } 27 | 28 | @Override 29 | public String getMethodName() { 30 | return Constants.listTags; 31 | } 32 | 33 | public Integer getBuildId() { 34 | return buildId; 35 | } 36 | 37 | public static ListTags create(Object object) { 38 | final Map map = toMap(object); 39 | return new ListTags((Integer) map.get(Constants.build)); 40 | } 41 | 42 | @Override 43 | public boolean equals(Object o) { 44 | if (this == o) return true; 45 | if (o == null || getClass() != o.getClass()) return false; 46 | ListTags listTags = (ListTags) o; 47 | return Objects.equals(buildId, listTags.buildId) && 48 | Objects.equals(getMethodName(), listTags.getMethodName()); 49 | } 50 | 51 | @Override 52 | public int hashCode() { 53 | return Objects.hash(getMethodName(), buildId); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/java/hudson/plugins/scm/koji/KojiScmRe.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2016 user. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package hudson.plugins.scm.koji; 25 | 26 | import hudson.Extension; 27 | import hudson.model.RootAction; 28 | 29 | @Extension 30 | //accessible via http://...:1234/kojiScmRe/ 31 | public class KojiScmRe implements RootAction { 32 | 33 | @Override 34 | public String getIconFileName() { 35 | return "clipboard.png"; 36 | } 37 | 38 | @Override 39 | public String getDisplayName() { 40 | return "koji-scm plugin re-run api gate"; 41 | } 42 | 43 | @Override 44 | public String getUrlName() { 45 | return "kojiScmRe"; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /webapp/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | OTool 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /webapp/src/components/TreeNode.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | interface TitleProps { 4 | children: React.ReactNode; 5 | } 6 | 7 | interface NodeInfoProps { 8 | children: React.ReactNode; 9 | } 10 | 11 | interface OptionsProps { 12 | children: React.ReactNode; 13 | } 14 | 15 | interface ChildNodesProps { 16 | children: React.ReactNode; 17 | } 18 | 19 | const Title = (props: TitleProps): JSX.Element => ( 20 |
21 | {props.children} 22 |
23 | ); 24 | 25 | const NodeInfo = (props: NodeInfoProps): JSX.Element => ( 26 |
27 | {props.children} 28 |
29 | ); 30 | 31 | const Options = (props: OptionsProps): JSX.Element => ( 32 |
33 | {props.children} 34 |
35 | ); 36 | 37 | const ChildNodes = (props: ChildNodesProps): JSX.Element => ( 38 |
39 | {props.children} 40 |
41 | ); 42 | 43 | interface Props { 44 | children: [ 45 | React.ReactElement, 46 | React.ReactElement, 47 | React.ReactElement, 48 | React.ReactElement 49 | ]; 50 | } 51 | 52 | class TreeNode extends React.PureComponent { 53 | 54 | static Title: typeof Title = Title; 55 | static NodeInfo: typeof NodeInfo = NodeInfo; 56 | static Options: typeof Options = Options; 57 | static ChildNodes: typeof ChildNodes = ChildNodes; 58 | 59 | render() { 60 | const [title, nodeInfo, options, childNodes] = this.props.children; 61 | return ( 62 |
63 | {title} 64 | {nodeInfo} 65 | {options} 66 | {childNodes} 67 |
68 | ); 69 | } 70 | } 71 | 72 | export default TreeNode; 73 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: Java CI with Maven 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Download repo 15 | uses: actions/checkout@v2 16 | 17 | - name: Set up JDK 17 18 | uses: actions/setup-java@v1 19 | with: 20 | java-version: 17 21 | 22 | - name: Cache Maven repository 23 | uses: actions/cache@v4 24 | with: 25 | path: ~/.m2/repository 26 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 27 | 28 | - name: Build with Maven 29 | run: | 30 | export MAVEN_OPTS="-Xmx4G" 31 | mvn install -DskipTests 32 | 33 | - name: test koji-scm-lib 34 | run: | 35 | export MAVEN_OPTS="-Xmx4G" 36 | cd koji-scm-lib 37 | mvn test 38 | 39 | - name: test fake-koji 40 | run: | 41 | export MAVEN_OPTS="-Xmx4G" 42 | cd fake-koji 43 | mvn test -Dheadless=true #the webapp takes long and was created in original full build and we do not clean 44 | 45 | - name: test jenkins-scm-koji-plugin 46 | run: | 47 | export MAVEN_OPTS="-Xmx4G" 48 | cd jenkins-scm-koji-plugin 49 | mvn test || echo "This fails now because of duplicate netty on class-path. It seems plugin works fine, but it is worthy to check those test resulsts manually" 50 | 51 | - name: Store artifacts 52 | run: | 53 | mkdir archives 54 | cp fake-koji/target/fake-koji-jar-with-dependencies.jar archives/ 55 | cp jenkins-scm-koji-plugin/target/jenkins-scm-koji-plugin.hpi archives/ 56 | shell: bash 57 | 58 | - name: Upload artifacts 59 | uses: actions/upload-artifact@v4 60 | with: 61 | name: Archives 62 | path: archives 63 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/manager/JDKVersionManager.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.manager; 2 | 3 | import org.fakekoji.jobmanager.ManagementException; 4 | import org.fakekoji.jobmanager.Manager; 5 | import org.fakekoji.model.JDKVersion; 6 | import org.fakekoji.storage.Storage; 7 | import org.fakekoji.storage.StorageException; 8 | 9 | import java.util.List; 10 | 11 | public class JDKVersionManager implements Manager { 12 | 13 | private final Storage storage; 14 | 15 | public JDKVersionManager(final Storage storage) { 16 | this.storage = storage; 17 | } 18 | 19 | @Override 20 | public JDKVersion create(JDKVersion jdkVersion) throws StorageException, ManagementException { 21 | if (storage.contains(jdkVersion.getId())) { 22 | throw new ManagementException("JDK version with id " + jdkVersion.getId() + " already exists"); 23 | } 24 | storage.store(jdkVersion.getId(), jdkVersion); 25 | return null; 26 | } 27 | 28 | @Override 29 | public JDKVersion read(String id) throws StorageException, ManagementException { 30 | if (!storage.contains(id)) { 31 | throw new ManagementException("No JDK version with id: " + id); 32 | } 33 | return storage.load(id, JDKVersion.class); 34 | } 35 | 36 | @Override 37 | public List readAll() throws StorageException { 38 | return storage.loadAll(JDKVersion.class); 39 | } 40 | 41 | @Override 42 | public JDKVersion update(String id, JDKVersion product) throws StorageException, ManagementException { 43 | return null; 44 | } 45 | 46 | @Override 47 | public JDKVersion delete(String id) throws StorageException, ManagementException { 48 | return null; 49 | } 50 | 51 | @Override 52 | public boolean contains(String id) { 53 | return storage.contains(id); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/java/hudson/plugins/scm/koji/KojiXmlRpcApi.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.scm.koji; 2 | 3 | import hudson.DescriptorExtensionList; 4 | import hudson.ExtensionPoint; 5 | import hudson.model.Describable; 6 | import hudson.model.Descriptor; 7 | import jenkins.model.Jenkins; 8 | import org.kohsuke.stapler.export.Exported; 9 | 10 | import javax.annotation.Nonnull; 11 | import java.io.Serializable; 12 | 13 | public abstract class KojiXmlRpcApi implements Describable, ExtensionPoint, Serializable { 14 | 15 | private static final long serialVersionUID = -1650617726812887577L; 16 | 17 | private final KojiXmlRpcApiType xmlRpcApiType; 18 | 19 | public KojiXmlRpcApi(final KojiXmlRpcApiType xmlRpcApiType) { 20 | this.xmlRpcApiType = xmlRpcApiType; 21 | } 22 | 23 | @Exported 24 | public KojiXmlRpcApiType getXmlRpcApiType() { 25 | return xmlRpcApiType; 26 | } 27 | 28 | @SuppressWarnings("unchecked") 29 | @Override 30 | public Descriptor getDescriptor() { 31 | return Jenkins.getActiveInstance().getDescriptorOrDie(getClass()); 32 | } 33 | 34 | public static class KojiXmlRpcApiDescriptor extends Descriptor { 35 | 36 | private final String xmlRpcApiName; 37 | 38 | public KojiXmlRpcApiDescriptor( 39 | final Class clazz, 40 | final String xmlRpcApiName 41 | ) { 42 | super(clazz); 43 | this.xmlRpcApiName = xmlRpcApiName; 44 | } 45 | 46 | @Nonnull 47 | @Override 48 | public String getDisplayName() { 49 | return xmlRpcApiName; 50 | } 51 | 52 | public DescriptorExtensionList getKojiXmlRpxApiDescriptors() { 53 | return Jenkins.getActiveInstance().getDescriptorList(KojiXmlRpcApi.class); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /webapp/src/components/formComponents/MultiSelect.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { FormControl, FormLabel, FormGroup, FormControlLabel, Checkbox } from "@material-ui/core" 3 | import { useObserver } from "mobx-react" 4 | 5 | type MultiSelectPropsRequired = { 6 | options: string[] 7 | } 8 | 9 | type MultiSelectPropsOptional = { 10 | label?: string 11 | onChange: (values: string[]) => void 12 | values: string[] 13 | } 14 | 15 | type MultiSelectProps = MultiSelectPropsRequired & MultiSelectPropsOptional 16 | 17 | const MultiSelect: React.FC = ({ label, onChange, options, values, }) => { 18 | 19 | const handleChange = (id: string) => { 20 | const index = values.indexOf(id) 21 | if (index < 0) { 22 | values.splice(0, 0, id) 23 | } else { 24 | values.splice(index, 1) 25 | } 26 | onChange(values) 27 | } 28 | 29 | return useObserver(() => { 30 | const multiSelect = ( 31 | 32 | { 33 | options.map((option, index) => 34 | = 0} 39 | onChange={() => { 40 | handleChange(option) 41 | }} 42 | value={index} /> 43 | } 44 | label={option} /> 45 | ) 46 | } 47 | 48 | ) 49 | 50 | return ( 51 | 52 | {label || ""} 53 | {multiSelect} 54 | 55 | ) 56 | }) 57 | } 58 | 59 | export default MultiSelect 60 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/manager/BuildProviderManager.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.manager; 2 | 3 | import org.fakekoji.jobmanager.ManagementException; 4 | import org.fakekoji.jobmanager.Manager; 5 | import org.fakekoji.model.BuildProvider; 6 | import org.fakekoji.storage.Storage; 7 | import org.fakekoji.storage.StorageException; 8 | 9 | import java.util.List; 10 | 11 | public class BuildProviderManager implements Manager { 12 | 13 | private final Storage storage; 14 | 15 | public BuildProviderManager(final Storage storage) { 16 | this.storage = storage; 17 | } 18 | 19 | @Override 20 | public BuildProvider create(BuildProvider buildProvider) throws StorageException, ManagementException { 21 | if (storage.contains(buildProvider.getId())) { 22 | throw new ManagementException("Build provider with id " + buildProvider.getId() + " already exists"); 23 | } 24 | storage.store(buildProvider.getId(), buildProvider); 25 | return null; 26 | } 27 | 28 | @Override 29 | public BuildProvider read(String id) throws StorageException, ManagementException { 30 | if (!storage.contains(id)) { 31 | throw new ManagementException("No build provider with id: " + id); 32 | } 33 | return storage.load(id, BuildProvider.class); 34 | } 35 | 36 | @Override 37 | public List readAll() throws StorageException { 38 | return storage.loadAll(BuildProvider.class); 39 | } 40 | 41 | @Override 42 | public BuildProvider update(String id, BuildProvider platform) throws StorageException, ManagementException { 43 | return null; 44 | } 45 | 46 | @Override 47 | public BuildProvider delete(String id) throws StorageException, ManagementException { 48 | return null; 49 | } 50 | 51 | @Override 52 | public boolean contains(String id) { 53 | return storage.contains(id); 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /webapp/src/components/formComponents/FileRequirementsForm.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { FormControl, FormLabel, FormGroup } from "@material-ui/core" 3 | import { useObserver } from "mobx-react" 4 | 5 | import Checkbox from "./Checkbox" 6 | import Select from "./Select" 7 | 8 | import { FileRequirements, BinaryRequirement } from "../../stores/model" 9 | 10 | interface Props { 11 | fileRequirements: FileRequirements 12 | } 13 | 14 | const FileRequirementsForm: React.FunctionComponent = (props) => { 15 | 16 | return useObserver(() => { 17 | const { fileRequirements } = props 18 | 19 | const onBinaryChange = (value: string) => { 20 | fileRequirements.binary = value as BinaryRequirement 21 | } 22 | 23 | const onSourcesChange = (value: boolean) => { 24 | fileRequirements.source = value 25 | } 26 | 27 | const onNoarchChange = (value: boolean) => { 28 | fileRequirements.noarch = value 29 | } 30 | 31 | return ( 32 | 33 | 34 | file requirements 35 | 36 | 37 | 41 | 45 | 47 | { 48 | (flag !== "NONE") && 49 | item.id)} 52 | values={limitation.list} /> 53 | } 54 | 55 | 56 | ); 57 | } 58 | } 59 | 60 | export default observer(LimitationForm); 61 | -------------------------------------------------------------------------------- /webapp/src/utils/createJobName.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BuildConfigs, 3 | TaskVariant, 4 | PlatformConfig, 5 | TaskConfig, 6 | VariantsConfig, 7 | } from "../stores/model" 8 | 9 | type JenkinsJob = { 10 | name: string 11 | url: string 12 | } 13 | 14 | export const getJobNameGenerator = ( 15 | variants: { [id: string]: TaskVariant }, 16 | url: string | undefined, 17 | ): (( 18 | projectId: string, 19 | jdkId: string, 20 | platformConfig: PlatformConfig, 21 | taskConfig: TaskConfig | undefined, 22 | variantsConfig: VariantsConfig, 23 | buildConfigs: BuildConfigs | undefined, 24 | ) => JenkinsJob | null) => { 25 | if (!url) { 26 | return () => null 27 | } 28 | const variantsMap = Object.keys(variants).reduce((map, key) => { 29 | const variant = variants[key] 30 | map.set(key, variant) 31 | return map 32 | }, new Map()) 33 | const sortVariants = (a: string, b: string): number => { 34 | const variantA = variantsMap.get(a) 35 | const variantB = variantsMap.get(b) 36 | if (!variantA || !variantB) { 37 | return 0 38 | } 39 | return variantA.order - variantB.order 40 | } 41 | const variantsToString = (config: VariantsConfig): string => { 42 | return Object.keys(config.map) 43 | .sort(sortVariants) 44 | .map(key => config.map[key]) 45 | .join(".") 46 | } 47 | return (projectId, jdkId, platform, task, variants, buildConfigs) => { 48 | if (!task) { 49 | return null 50 | } 51 | const buildPart = !!buildConfigs 52 | ? `-${buildConfigs.platform.id}-${variantsToString(buildConfigs.taskVariants)}-` 53 | : "-" 54 | const name = `${task.id}-${jdkId}-${projectId}${buildPart}${platform.id}.${platform.provider}-${variantsToString(variants)}` 55 | const jobUrl = `${url}job/${name}` 56 | return { 57 | name, 58 | url: jobUrl, 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /fake-koji/src/test/java/org/fakekoji/jobmanager/project/JDKProjectParserTest.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.project; 2 | 3 | import org.fakekoji.DataGenerator; 4 | import org.fakekoji.core.AccessibleSettings; 5 | import org.fakekoji.jobmanager.ManagementException; 6 | import org.fakekoji.jobmanager.model.JDKProject; 7 | import org.fakekoji.jobmanager.model.JDKTestProject; 8 | import org.fakekoji.jobmanager.model.Job; 9 | import org.fakekoji.storage.StorageException; 10 | import org.junit.Assert; 11 | import org.junit.Before; 12 | import org.junit.Rule; 13 | import org.junit.Test; 14 | import org.junit.rules.TemporaryFolder; 15 | 16 | import java.io.IOException; 17 | import java.util.Set; 18 | 19 | 20 | public class JDKProjectParserTest { 21 | 22 | @Rule 23 | public final TemporaryFolder temporaryFolder = new TemporaryFolder(); 24 | 25 | private AccessibleSettings settings; 26 | 27 | @Before 28 | public void setup() throws IOException { 29 | settings = DataGenerator.getSettings(DataGenerator.initFolders(temporaryFolder)); 30 | } 31 | 32 | @Test 33 | public void parseJDKTestProject() throws StorageException, ManagementException { 34 | final JDKTestProject jdkTestProject = DataGenerator.getJDKTestProject(); 35 | final JDKProjectParser parser = settings.getJdkProjectParser(); 36 | final Set actualJobs = parser.parse(jdkTestProject); 37 | Assert.assertEquals( 38 | "ParsedProject should be equal", 39 | DataGenerator.getJDKTestProjectJobs(), 40 | actualJobs 41 | ); 42 | } 43 | 44 | @Test 45 | public void parseJDKProject() throws StorageException, ManagementException { 46 | final JDKProject jdkProject = DataGenerator.getJDKProject(); 47 | final JDKProjectParser parser = settings.getJdkProjectParser(); 48 | final Set actualJobs = parser.parse(jdkProject); 49 | Assert.assertEquals( 50 | "ParsedProject should be equal", 51 | DataGenerator.getJDKProjectJobs(), 52 | actualJobs 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/pull-job.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | %{MASTER_LABEL} 8 | false 9 | false 10 | false 11 | false 12 | %{TRIGGER} 13 | false 14 | 15 | 16 | %{PULL_SCRIPT} 17 | 18 | 19 | 20 | 21 | ** 22 | false 23 | false 24 | false 25 | true 26 | true 27 | 28 | 29 | 30 | ### CHANGES DETECTED ### 31 | 32 | false 33 | true 34 | false 35 | true 36 | 37 | 38 | 39 | nothing_ever 40 | ^future VR: 41 | false 42 | false 43 | false 44 | true 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/manager/TaskManager.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.manager; 2 | 3 | import org.fakekoji.jobmanager.ManagementException; 4 | import org.fakekoji.jobmanager.Manager; 5 | import org.fakekoji.model.Task; 6 | import org.fakekoji.storage.Storage; 7 | import org.fakekoji.storage.StorageException; 8 | 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | public class TaskManager implements Manager { 13 | 14 | private final Storage taskStorage; 15 | 16 | public TaskManager(final Storage taskStorage) { 17 | this.taskStorage = taskStorage; 18 | } 19 | 20 | @Override 21 | public Task create(Task task) throws StorageException, ManagementException { 22 | if (taskStorage.contains(task.getId())) { 23 | throw new ManagementException("Task with id " + task.getId() + " already exists"); 24 | } 25 | taskStorage.store(task.getId(), task); 26 | return task; 27 | } 28 | 29 | @Override 30 | public Task read(String id) throws StorageException, ManagementException { 31 | if (!taskStorage.contains(id)) { 32 | throw new ManagementException("No task with id: " + id); 33 | } 34 | return taskStorage.load(id, Task.class); 35 | } 36 | 37 | @Override 38 | public List readAll() throws StorageException { 39 | List l = taskStorage.loadAll(Task.class); 40 | Collections.sort(l); 41 | return l; 42 | } 43 | 44 | @Override 45 | public Task update(String id, Task task) throws StorageException, ManagementException { 46 | if (!taskStorage.contains(id)) { 47 | throw new ManagementException("No task with id: " + id); 48 | } 49 | taskStorage.store(id, task); 50 | return task; 51 | } 52 | 53 | @Override 54 | public Task delete(String id) throws StorageException, ManagementException { 55 | throw new ManagementException("Not supported"); 56 | } 57 | 58 | @Override 59 | public boolean contains(String id) { 60 | return taskStorage.contains(id); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /webapp/src/components/formComponents/PlatformProviderForm.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { useObserver } from "mobx-react" 3 | import { Grid } from "@material-ui/core" 4 | 5 | import { PlatformProvider } from "../../stores/model" 6 | import TextInput from "./TextInput" 7 | import { PlatformProviderValidation } from "../../utils/validators" 8 | 9 | interface PlatformProviderFormProps { 10 | platformProvider: PlatformProvider 11 | validation?: PlatformProviderValidation 12 | } 13 | 14 | const PlatformProviderForm: React.FC = props => 15 | useObserver(() => { 16 | const { platformProvider, validation } = props 17 | 18 | const onIdChange = (value: string) => { 19 | platformProvider.id = value 20 | } 21 | 22 | const onHwNodesChange = (value: string) => { 23 | platformProvider.hwNodes = value.split(" ") 24 | } 25 | 26 | const onVmNodesChange = (value: string) => { 27 | platformProvider.vmNodes = value.split(" ") 28 | } 29 | 30 | const { hwNodes, id, vmNodes } = 31 | validation || ({} as PlatformProviderValidation) 32 | 33 | return ( 34 | 35 | 36 | 42 | 48 | 54 | 55 | 56 | ) 57 | }) 58 | 59 | export default PlatformProviderForm 60 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcrequestparams/ListArtefacts.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcrequestparams; 2 | 3 | import hudson.plugins.scm.koji.Constants; 4 | 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Objects; 10 | 11 | import static org.fakekoji.xmlrpc.server.xmlrpcrequestparams.XmlRpcRequestUtils.starStarLabel; 12 | 13 | public abstract class ListArtefacts implements XmlRpcRequestParams { 14 | 15 | private final Integer buildId; 16 | private final List archs; 17 | 18 | ListArtefacts(Integer buildId, List archs) { 19 | this.buildId = buildId; 20 | this.archs = archs; 21 | } 22 | 23 | static List getArchs(Object object) { 24 | if (object == null) { 25 | return null; 26 | } 27 | final List archList = new ArrayList<>(); 28 | final Object[] archs = (Object[]) object; 29 | for (final Object arch : archs) 30 | archList.add((String) arch); 31 | return archList; 32 | } 33 | 34 | @Override 35 | public Object[] toXmlRpcParams() { 36 | final Map map = new HashMap<>(); 37 | map.put(Constants.buildID, buildId); 38 | map.put(starStarLabel, Boolean.TRUE); 39 | if (archs != null && !archs.isEmpty()) { 40 | map.put(Constants.arches, archs.toArray()); 41 | } 42 | return new Object[]{map}; 43 | } 44 | 45 | public Integer getBuildId() { 46 | return buildId; 47 | } 48 | 49 | public List getArchs() { 50 | return archs; 51 | } 52 | 53 | @Override 54 | public boolean equals(Object o) { 55 | if (this == o) return true; 56 | if (o == null || getClass() != o.getClass()) return false; 57 | ListArtefacts that = (ListArtefacts) o; 58 | return Objects.equals(buildId, that.buildId) && 59 | Objects.equals(archs, that.archs) && 60 | Objects.equals(getMethodName(), that.getMethodName()); 61 | } 62 | 63 | @Override 64 | public int hashCode() { 65 | return Objects.hash(getMethodName(), buildId, archs); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/KojiChangeLogSet/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | No changes 6 | 7 | 8 | 9 | 10 | 11 | 12 | 37 | 38 | 39 |
${changeset.field}: 13 | 14 | 15 | 16 | 17 | 18 | ${hyperlink.displayedString} 19 | 20 | 21 | 22 | (${hyperlink.showSum()}) 23 |
24 |
25 |
26 | 27 | ${hyperlink.displayedString}
28 |
29 |
30 |
31 |
32 | 33 | You must log in to use otool actions 34 | 35 |
36 |
40 |
41 |
42 |
43 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/KojiChangeLogSet/digest.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | No changes 6 | 7 | 8 | 9 | 10 | 11 | 12 | 37 | 38 | 39 |
${changeset.field}: 13 | 14 | 15 | 16 | 17 | 18 | ${hyperlink.displayedString} 19 | 20 | 21 | 22 | (${hyperlink.showSum()}) 23 |
24 |
25 |
26 | 27 | ${hyperlink.displayedString}
28 |
29 |
30 |
31 |
32 | 33 | You must log in to use otool actions 34 | 35 |
36 |
40 |
41 |
42 |
43 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/manager/PlatformManager.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.manager; 2 | 3 | import org.fakekoji.jobmanager.ManagementException; 4 | import org.fakekoji.jobmanager.ManagementUtils; 5 | import org.fakekoji.jobmanager.Manager; 6 | import org.fakekoji.model.Platform; 7 | import org.fakekoji.storage.Storage; 8 | import org.fakekoji.storage.StorageException; 9 | 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | public class PlatformManager implements Manager { 14 | 15 | private final Storage storage; 16 | 17 | public PlatformManager(final Storage storage) { 18 | this.storage = storage; 19 | } 20 | 21 | @Override 22 | public Platform create(Platform platform) throws StorageException, ManagementException { 23 | // as frontend doesn't generate platform's ID, this will create platform with the correct ID based on its 24 | // os, version, architecture and provider 25 | final Platform newPlatform = Platform.create(platform); 26 | ManagementUtils.checkID(newPlatform.getId(), storage, false); 27 | storage.store(newPlatform.getId(), newPlatform); 28 | return newPlatform; 29 | } 30 | 31 | @Override 32 | public Platform read(String id) throws StorageException, ManagementException { 33 | ManagementUtils.checkID(id, storage); 34 | return storage.load(id, Platform.class); 35 | } 36 | 37 | @Override 38 | public List readAll() throws StorageException { 39 | List l = storage.loadAll(Platform.class); 40 | Collections.sort(l); 41 | return l; 42 | } 43 | 44 | @Override 45 | public Platform update(String id, Platform platform) throws StorageException, ManagementException { 46 | ManagementUtils.checkID(id, storage); 47 | storage.store(id, platform); 48 | return platform; 49 | } 50 | 51 | @Override 52 | public Platform delete(String id) throws StorageException, ManagementException { 53 | ManagementUtils.checkID(id, storage); 54 | throw new ManagementException("Not supported"); 55 | } 56 | 57 | @Override 58 | public boolean contains(String id) { 59 | return storage.contains(id); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.jenkins-ci.plugins 7 | plugin 8 | 4.87 9 | 10 | 11 | fake-koji 12 | koji-scm 13 | 2.2-SNAPSHOT 14 | pom 15 | 16 | Koji SCM 17 | 18 | 19 | MIT 20 | http://www.opensource.org/licenses/mit-license.php 21 | 22 | 23 | 24 | 25 | jenkins-scm-koji-plugin 26 | fake-koji 27 | koji-scm-lib 28 | 29 | 30 | 31 | 2.461 32 | ${jenkins.baseline} 33 | 3.1.3 34 | 35 | 36 | 37 | 38 | 39 | org.apache.xmlrpc 40 | xmlrpc-server 41 | ${xmlrpc.version} 42 | 43 | 44 | org.apache.xmlrpc 45 | xmlrpc-client 46 | ${xmlrpc.version} 47 | 48 | 49 | 50 | 51 | 52 | 53 | repo.jenkins-ci.org 54 | https://repo.jenkins-ci.org/public/ 55 | 56 | 57 | 58 | 59 | repo.jenkins-ci.org 60 | https://repo.jenkins-ci.org/public/ 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/resources/hudson/plugins/scm/koji/KojiSCM/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 13 | 14 | 15 | 16 | 19 | 20 | 24 | 25 | 30 | 31 | 34 | 37 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /webapp/src/styles/Layout.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | 5 | *, *:before, *:after { 6 | box-sizing: inherit; 7 | } 8 | 9 | .app-container { 10 | display: grid; 11 | grid-template-columns: 2fr 5fr; 12 | grid-template-areas: 13 | "header header" 14 | "list form" 15 | } 16 | 17 | .header-container { 18 | display: flex; 19 | flex-direction: row; 20 | grid-area: header; 21 | } 22 | 23 | .header-container .header-item { 24 | cursor: pointer; 25 | padding: 20px 25px; 26 | } 27 | 28 | .header-container .header-item:hover { 29 | background-color: rgba(1, 1, 1, 0.1); 30 | } 31 | 32 | .list-container { 33 | grid-area: list 34 | } 35 | 36 | .list-container .header { 37 | display: flex; 38 | font-size: 30px; 39 | justify-content: space-between; 40 | padding: 20px 30px; 41 | } 42 | 43 | .list-container .body { 44 | display: flex; 45 | flex-direction: column 46 | } 47 | 48 | .list-container .list-item { 49 | align-items: center; 50 | background-color: rgba(1, 1, 1, 0.1); 51 | cursor: pointer; 52 | display: flex; 53 | justify-content: space-between; 54 | padding: 20px 25px; 55 | } 56 | 57 | .list-container .list-item:hover { 58 | background-color: rgba(1, 1, 1, 0.0); 59 | } 60 | 61 | .form-container { 62 | grid-area: form 63 | } 64 | 65 | .tree-node-wrapper { 66 | border-radius: 3px; 67 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 3px 10px 0 rgba(0, 0, 0, 0.19); 68 | display: grid; 69 | grid-template-areas: 70 | "title options" 71 | "node-info node-info" 72 | "nodes nodes"; 73 | margin: 5px 10px 10px 25px; 74 | } 75 | 76 | .tree-node-title { 77 | align-items: flex-start; 78 | display: flex; 79 | flex-direction: column; 80 | grid-area: title; 81 | justify-content: center; 82 | padding: 7px; 83 | } 84 | 85 | .tree-node-options { 86 | align-items: flex-start; 87 | display: flex; 88 | flex-direction: row; 89 | grid-area: options; 90 | justify-content: flex-end; 91 | padding: 7px; 92 | } 93 | 94 | .tree-node-info { 95 | border-top: 1px solid #ccc; 96 | display: flex; 97 | flex-direction: row; 98 | grid-area: node-info; 99 | margin-top: 5px; 100 | padding: 10px 0 10px 25px; 101 | } 102 | 103 | .tree-node-nodes { 104 | grid-area: nodes; 105 | } 106 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/model/BuildProvider.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.model; 2 | 3 | import java.util.Objects; 4 | 5 | public class BuildProvider { 6 | 7 | private final String id; 8 | private final String label; 9 | private final String topUrl; 10 | private final String downloadUrl; 11 | private final String packageInfoUrl; 12 | 13 | public BuildProvider() { 14 | id = null; 15 | label = null; 16 | topUrl = null; 17 | downloadUrl = null; 18 | packageInfoUrl = null; 19 | } 20 | 21 | public BuildProvider( 22 | String id, 23 | String label, 24 | String topUrl, 25 | String downloadUrl, 26 | final String packageInfoUrl 27 | ) { 28 | this.id = id; 29 | this.label = label; 30 | this.topUrl = topUrl; 31 | this.downloadUrl = downloadUrl; 32 | this.packageInfoUrl = packageInfoUrl; 33 | } 34 | 35 | public String getId() { 36 | return id; 37 | } 38 | 39 | public String getLabel() { 40 | return label; 41 | } 42 | 43 | public String getTopUrl() { 44 | return topUrl; 45 | } 46 | 47 | public String getDownloadUrl() { 48 | return downloadUrl; 49 | } 50 | 51 | public String getPackageInfoUrl() { 52 | return packageInfoUrl; 53 | } 54 | 55 | @Override 56 | public boolean equals(Object o) { 57 | if (this == o) return true; 58 | if (!(o instanceof BuildProvider)) return false; 59 | BuildProvider that = (BuildProvider) o; 60 | return Objects.equals(id, that.id) && 61 | Objects.equals(label, that.label) && 62 | Objects.equals(topUrl, that.topUrl) && 63 | Objects.equals(downloadUrl, that.downloadUrl) && 64 | Objects.equals(packageInfoUrl, that.packageInfoUrl); 65 | } 66 | 67 | @Override 68 | public int hashCode() { 69 | return Objects.hash(id, label, topUrl, downloadUrl, packageInfoUrl); 70 | } 71 | 72 | @Override 73 | public String toString() { 74 | return "BuildProvider{" + 75 | "id='" + id + '\'' + 76 | ", label='" + label + '\'' + 77 | ", topUrl='" + topUrl + '\'' + 78 | ", downloadUrl='" + downloadUrl + '\'' + 79 | ", packageInfoUrl='" + packageInfoUrl + '\'' + 80 | '}'; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/api/http/filehandling/FileDownloadService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2018 . 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.fakekoji.api.http.filehandling; 25 | 26 | import com.sun.net.httpserver.HttpServer; 27 | import java.io.File; 28 | import java.io.IOException; 29 | import java.net.InetSocketAddress; 30 | 31 | /** 32 | * This class implements http server used as koji download server ( packages are 33 | * downloaded from here by jenkins koji plugin ). 34 | * 35 | * Based on code, which was originally in JavaServer class. 36 | */ 37 | public class FileDownloadService { 38 | 39 | private File dbFileRoot; 40 | private int port; 41 | private HttpServer hs; 42 | 43 | public FileDownloadService(File dbFileRoot, int port) { 44 | this.dbFileRoot = dbFileRoot; 45 | this.port = port; 46 | } 47 | 48 | public int getPort() { 49 | return port; 50 | } 51 | 52 | public void start() throws IOException { 53 | if (hs == null) { 54 | hs = HttpServer.create(new InetSocketAddress(port), 0); 55 | hs.createContext("/", new FileReturningHandler(dbFileRoot)); 56 | } 57 | hs.start(); 58 | } 59 | 60 | public void stop() { 61 | if (hs != null) { 62 | hs.stop(10); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /webapp/src/components/formComponents/JDKVersionSelectForm.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { FormControl, FormLabel, FormGroup } from "@material-ui/core" 3 | import { useObserver } from "mobx-react" 4 | 5 | import Select from "./Select" 6 | import { Product } from "../../stores/model" 7 | import useStores from "../../hooks/useStores" 8 | import { ProductValidation } from "../../utils/validators" 9 | 10 | interface Props { 11 | product: Product 12 | validation?: ProductValidation 13 | } 14 | 15 | const ProductSelectForm: React.FC = props => { 16 | const { configStore } = useStores() 17 | 18 | return useObserver(() => { 19 | const { product, validation } = props 20 | const { jdkVersions, getJDKVersion } = configStore 21 | const jdkVersion = getJDKVersion(product.jdk) 22 | 23 | const { 24 | jdk, 25 | packageName 26 | } = validation || {} as ProductValidation 27 | 28 | const onJDKVersionChange = (value: string) => { 29 | product.jdk = value 30 | const jdkVersion = getJDKVersion(product.jdk) 31 | if (jdkVersion) { 32 | const packageNames = jdkVersion.packageNames 33 | product.packageName = 34 | packageNames.length > 0 ? packageNames[0] : "" 35 | } 36 | } 37 | 38 | const onPackageNameChange = (value: string) => { 39 | product.packageName = value 40 | } 41 | 42 | return ( 43 | 44 | Product 45 | 46 | 61 | )} 62 | 63 | 64 | ) 65 | }) 66 | } 67 | 68 | export default ProductSelectForm 69 | -------------------------------------------------------------------------------- /fake-koji/src/main/resources/jenkins-templates/update-vm-job.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | false 6 | 7 | 8 | %{NODE} 9 | false 10 | false 11 | false 12 | false 13 | 14 | false 15 | 16 | 17 | #!/bin/sh 18 | # set EXCLUDE_KERNEL=ture, if you wont to skip kernel update 19 | # set ALLOW_ALPHAREPO=false when you dont want to update from alpha-testing openjdkQA internal repo. Such update and testruns must be observed carefully 20 | # it is recommended to run normal update as separate step before update with ALLOW_ALPHAREPO 21 | # ALLOW_ALPHAREPO shold be run for el 8.y.z and 9.y.z only (keep it in mind 22 | export VM_J_ID=%{PLATFORM_NAME} 23 | sh %{SCRIPTS_ROOT}/jenkins/%{PROVIDER}/updateBox.sh $VM_J_ID \ 24 | "sudo EXCLUDE_KERNEL=false ALLOW_ALPHAREPO=true bash /mnt/shared/TckScripts/jenkins/%{PROVIDER}/update/update-command.sh" 25 | #"sudo dnf -y install kernel-modules-extra && sudo EXCLUDE_KERNEL=false ALLOW_ALPHAREPO=false bash /mnt/shared/TckScripts/jenkins/vagrant/update/update-command.sh" 26 | #"sudo dnf -y --enablerepo=rhel-8-buildroot upgrade libstdc++-static giflib-devel && sudo EXCLUDE_KERNEL=true ALLOW_ALPHAREPO=false bash /mnt/shared/TckScripts/jenkins/vagrant/update/update-command.sh" 27 | #"echo just repack" 28 | #"sudo dnf -y remove *photos* gnome-soft* PackageKit flatpak gnome-contac* gnome-box* gnome-w* *abrt* *clock*" 29 | #"sudo yum -y install *lcms*" 30 | #"sudo yum -y downgrade \"nss*\"" 31 | #"sudo yum -y downgrade \"nspr*\"" 32 | 33 | 34 | 35 | 36 | %{POST_BUILD_TASK_PLUGIN} 37 | 38 | 39 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcresponse/RPMList.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcresponse; 2 | 3 | import hudson.plugins.scm.koji.Constants; 4 | import hudson.plugins.scm.koji.model.RPM; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Collections; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | import static org.fakekoji.xmlrpc.server.xmlrpcrequestparams.XmlRpcRequestUtils.toMaps; 13 | 14 | public class RPMList implements XmlRpcResponse> { 15 | 16 | private final List rpms; 17 | 18 | public RPMList(List rpms) { 19 | this.rpms = rpms; 20 | } 21 | 22 | @Override 23 | public Object toObject() { 24 | return parseRpms(); 25 | } 26 | 27 | @Override 28 | public List getValue() { 29 | return rpms; 30 | } 31 | 32 | private static List parseRpmMaps(List> maps) { 33 | if (maps == null) { 34 | return Collections.emptyList(); 35 | } 36 | final List rpms = new ArrayList<>(maps.size()); 37 | for (Map map : maps) { 38 | rpms.add(parseRpmMap(map)); 39 | } 40 | return rpms; 41 | } 42 | 43 | private static RPM parseRpmMap(Map map) { 44 | return new RPM( 45 | (String) map.get(Constants.name), 46 | (String) map.get(Constants.version), 47 | (String) map.get(Constants.release), 48 | (String) map.get(Constants.nvr), 49 | (String) map.get(Constants.arch), 50 | (String) map.get(Constants.filename) 51 | ); 52 | } 53 | 54 | private List> parseRpms() { 55 | List> maps = new ArrayList<>(); 56 | for (RPM rpm : rpms) { 57 | maps.add(parseRpm(rpm)); 58 | } 59 | return maps; 60 | } 61 | 62 | private Map parseRpm(RPM rpm) { 63 | Map map = new HashMap<>(); 64 | map.put(Constants.release, rpm.getRelease()); 65 | map.put(Constants.version, rpm.getVersion()); 66 | map.put(Constants.name, rpm.getName()); 67 | map.put(Constants.filename, rpm.getFilename("")); 68 | map.put(Constants.nvr, rpm.getNvr()); 69 | map.put(Constants.arch, rpm.getArch()); 70 | return map; 71 | } 72 | 73 | public static RPMList create(Object object) { 74 | return new RPMList(parseRpmMaps(toMaps(object))); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /fake-koji/src/test/java/org/fakekoji/jobmanager/project/ReverseJDKProjectParserTest.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.project; 2 | 3 | import org.fakekoji.DataGenerator; 4 | import org.fakekoji.core.AccessibleSettings; 5 | import org.fakekoji.functional.Result; 6 | import org.fakekoji.jobmanager.model.Project; 7 | import org.junit.Assert; 8 | import org.junit.Before; 9 | import org.junit.Rule; 10 | import org.junit.Test; 11 | import org.junit.rules.TemporaryFolder; 12 | 13 | import java.io.IOException; 14 | import java.util.Arrays; 15 | import java.util.HashSet; 16 | import java.util.Optional; 17 | import java.util.Set; 18 | 19 | public class ReverseJDKProjectParserTest { 20 | 21 | @Rule 22 | public final TemporaryFolder temporaryFolder = new TemporaryFolder(); 23 | 24 | private AccessibleSettings settings; 25 | 26 | 27 | @Before 28 | public void setup() throws IOException { 29 | settings = DataGenerator.getSettings(DataGenerator.initFolders(temporaryFolder)); 30 | } 31 | 32 | @Test 33 | public void parseJDKTestProjectJobs() { 34 | final ReverseJDKProjectParser parser = settings.getReverseJDKProjectParser(); 35 | final Result result = parser.parseJobs(DataGenerator.getJDKTestProjectJobs()); 36 | Assert.assertEquals( 37 | DataGenerator.getJDKTestProject(), 38 | result.getValue() 39 | ); 40 | } 41 | 42 | @Test 43 | public void parseJDKProjectJobs() { 44 | final ReverseJDKProjectParser parser = settings.getReverseJDKProjectParser(); 45 | final Result result = parser.parseJobs(DataGenerator.getJDKProjectJobs()); 46 | Assert.assertEquals( 47 | DataGenerator.getJDKProject(), 48 | result.getValue() 49 | ); 50 | } 51 | 52 | @Test 53 | public void findOrCreateString() { 54 | final String a = "aaa"; 55 | final String b = "bbb"; 56 | final String c = "ccc"; 57 | final Set strings = new HashSet<>(Arrays.asList(a, b)); 58 | 59 | final Optional opt = ReverseJDKProjectParser.findConfig(strings, s -> s.equals(a)); 60 | Assert.assertTrue(opt.isPresent()); 61 | Assert.assertEquals(opt.get(), a); 62 | 63 | final Optional optEmpty = ReverseJDKProjectParser.findConfig(strings, s -> s.equals(c)); 64 | Assert.assertFalse(optEmpty.isPresent()); 65 | 66 | final String string = ReverseJDKProjectParser.findOrCreateConfig(strings, s -> s.equals(c), () -> c); 67 | Assert.assertEquals(string, c); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/java/hudson/plugins/scm/koji/KojiEnvVarsAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2016 user. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package hudson.plugins.scm.koji; 25 | 26 | import hudson.EnvVars; 27 | import hudson.model.AbstractBuild; 28 | import hudson.model.EnvironmentContributingAction; 29 | 30 | import static hudson.plugins.scm.koji.Constants.BUILD_ENV_NVR; 31 | import static hudson.plugins.scm.koji.Constants.BUILD_ENV_RPMS_DIR; 32 | import static hudson.plugins.scm.koji.Constants.BUILD_ENV_RPM_FILES; 33 | 34 | public class KojiEnvVarsAction implements EnvironmentContributingAction { 35 | 36 | private final String nvr; 37 | private final String rpmsDir; 38 | private final String rpmFiles; 39 | 40 | public KojiEnvVarsAction(String nvr, String rpmsDir, String rpmFiles) { 41 | this.nvr = nvr; 42 | this.rpmsDir = rpmsDir; 43 | this.rpmFiles = rpmFiles; 44 | } 45 | 46 | @Override 47 | public void buildEnvVars(AbstractBuild build, EnvVars env) { 48 | env.put(BUILD_ENV_NVR, nvr); 49 | env.put(BUILD_ENV_RPMS_DIR, rpmsDir); 50 | env.put(BUILD_ENV_RPM_FILES, rpmFiles); 51 | } 52 | 53 | @Override 54 | public String getIconFileName() { 55 | return null; 56 | } 57 | 58 | @Override 59 | public String getDisplayName() { 60 | return null; 61 | } 62 | 63 | @Override 64 | public String getUrlName() { 65 | return null; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /webapp/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /koji-scm-lib/src/main/java/org/fakekoji/xmlrpc/server/xmlrpcrequestparams/GetBuildList.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.xmlrpc.server.xmlrpcrequestparams; 2 | 3 | import java.util.Objects; 4 | 5 | import hudson.plugins.scm.koji.Constants; 6 | 7 | public class GetBuildList implements XmlRpcRequestParams { 8 | 9 | private final String projectName; 10 | private final String buildVariants; 11 | private final String platforms; 12 | private final boolean isBuilt; 13 | 14 | public GetBuildList( 15 | String projectName, 16 | String buildVariants, 17 | String platforms, 18 | boolean isBuilt 19 | ) { 20 | this.projectName = projectName; 21 | this.buildVariants = buildVariants; 22 | this.platforms = platforms; 23 | this.isBuilt = isBuilt; 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | return projectName + "; " + buildVariants + "; " + isBuilt; 29 | } 30 | 31 | @Override 32 | public Object[] toXmlRpcParams() { 33 | return new Object[]{this}; 34 | } 35 | 36 | @Override 37 | public String getMethodName() { 38 | return Constants.getBuildList; 39 | } 40 | 41 | public String getProjectName() { 42 | return projectName; 43 | } 44 | 45 | public String getBuildVariants() { 46 | return buildVariants; 47 | } 48 | 49 | public String getPlatforms() { 50 | return platforms; 51 | } 52 | 53 | /** 54 | * true = if the built is already finished 55 | * false = the built is about to be build 56 | * 57 | * @return 58 | */ 59 | public boolean isBuilt() { 60 | return isBuilt; 61 | } 62 | 63 | public boolean isSupposedToGetBuild() { 64 | return !isBuilt; 65 | } 66 | 67 | public static GetBuildList create(Object object) { 68 | return (GetBuildList) object; 69 | } 70 | 71 | @Override 72 | public boolean equals(Object o) { 73 | if (this == o) return true; 74 | if (o == null || getClass() != o.getClass()) return false; 75 | GetBuildList that = (GetBuildList) o; 76 | return isBuilt == that.isBuilt && 77 | Objects.equals(projectName, that.projectName) && 78 | Objects.equals(buildVariants, that.buildVariants) && 79 | Objects.equals(platforms, that.platforms) && 80 | Objects.equals(getMethodName(), that.getMethodName()); 81 | } 82 | 83 | @Override 84 | public int hashCode() { 85 | return Objects.hash(getMethodName(), projectName, buildVariants, platforms, isBuilt); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/model/TaskVariantValue.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.model; 2 | 3 | import java.util.List; 4 | import java.util.Objects; 5 | import java.util.Optional; 6 | 7 | public class TaskVariantValue { 8 | 9 | private final String id; 10 | private final String label; 11 | private final List subpackageBlacklist; 12 | private final List subpackageWhitelist; 13 | 14 | public TaskVariantValue() { 15 | id = null; 16 | label = null; 17 | subpackageBlacklist = null; 18 | subpackageWhitelist = null; 19 | } 20 | 21 | public TaskVariantValue(String id, String label) { 22 | this.id = id; 23 | this.label = label; 24 | subpackageBlacklist = null; 25 | subpackageWhitelist = null; 26 | } 27 | 28 | public TaskVariantValue( 29 | String id, 30 | String label, 31 | List subpackageBlacklist, 32 | List subpackageWhitelist 33 | ) { 34 | this.id = id; 35 | this.label = label; 36 | this.subpackageBlacklist = subpackageBlacklist; 37 | this.subpackageWhitelist = subpackageWhitelist; 38 | } 39 | 40 | public String getId() { 41 | return id; 42 | } 43 | 44 | public String getLabel() { 45 | return label; 46 | } 47 | 48 | public Optional> getSubpackageBlacklist() { 49 | return Optional.ofNullable(subpackageBlacklist); 50 | } 51 | 52 | public Optional> getSubpackageWhitelist() { 53 | return Optional.ofNullable(subpackageWhitelist); 54 | } 55 | 56 | @Override 57 | public boolean equals(Object o) { 58 | if (this == o) return true; 59 | if (!(o instanceof TaskVariantValue)) return false; 60 | TaskVariantValue that = (TaskVariantValue) o; 61 | return Objects.equals(id, that.id) && 62 | Objects.equals(label, that.label) && 63 | Objects.equals(subpackageBlacklist, that.subpackageBlacklist) && 64 | Objects.equals(subpackageWhitelist, that.subpackageWhitelist); 65 | } 66 | 67 | @Override 68 | public int hashCode() { 69 | return Objects.hash(id, label, subpackageBlacklist, subpackageWhitelist); 70 | } 71 | 72 | @Override 73 | public String toString() { 74 | return "TaskVariantValue{" + 75 | "id='" + id + '\'' + 76 | ", label='" + label + '\'' + 77 | ", subpackageBlacklist=" + subpackageBlacklist + 78 | ", subpackageWhitelist=" + subpackageWhitelist + 79 | '}'; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/api/http/rest/RestUtils.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.api.http.rest; 2 | 3 | import org.fakekoji.functional.Result; 4 | import org.fakekoji.functional.Tuple; 5 | import org.fakekoji.jobmanager.model.Product; 6 | 7 | import java.util.Arrays; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.Optional; 11 | 12 | public class RestUtils { 13 | 14 | public static Optional extractParamValue(Map> paramsMap, String param) { 15 | return Optional.ofNullable(paramsMap.get(param)) 16 | .filter(list -> list.size() == 1) 17 | .map(list -> list.get(0)); 18 | } 19 | 20 | public static Result extractMandatoryParamValue(Map> paramsMap, String param) { 21 | return extractParamValue(paramsMap, param).>map(Result::ok) 22 | .orElseGet(() -> Result.err(new OToolError( 23 | "Missing mandatory parameter: '" + param + "'!", 24 | 400 25 | ))); 26 | } 27 | 28 | static Result, OToolError> extractProducts(final Map> paramsMap) { 29 | return extractMandatoryParamValue(paramsMap, "from").flatMap(fromValue -> 30 | extractProduct(fromValue).flatMap(fromProduct -> 31 | extractMandatoryParamValue(paramsMap, "to").flatMap(toValue -> 32 | extractProduct(toValue).flatMap(toProduct -> 33 | Result.ok(new Tuple<>(fromProduct, toProduct)) 34 | ) 35 | ) 36 | ) 37 | ); 38 | } 39 | 40 | static Result extractProduct(final String paramValue) { 41 | final String[] split = paramValue.split(","); 42 | if (split.length != 2 || split[0].trim().isEmpty() || split[1].trim().isEmpty()) { 43 | return Result.err(new OToolError("Expected format jdkVersionId,packageName", 400)); 44 | } 45 | return Result.ok(new Product(split[0], split[1])); 46 | } 47 | 48 | static Result, OToolError> extractProjectIds(Map> paramsMap) { 49 | final Optional projectIdsOptional = extractParamValue(paramsMap, "projects"); 50 | return projectIdsOptional., OToolError>>map(s -> 51 | Result.ok(Arrays.asList(s.split(","))) 52 | ).orElseGet(() -> Result.err(new OToolError( 53 | "projects are mandatory. Use get/projects?as=list to get them all", 54 | 400 55 | ))); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /fake-koji/src/main/java/org/fakekoji/jobmanager/model/JDKTestProject.java: -------------------------------------------------------------------------------- 1 | package org.fakekoji.jobmanager.model; 2 | 3 | import org.fakekoji.model.OToolVariable; 4 | 5 | import java.util.List; 6 | import java.util.Objects; 7 | import java.util.Set; 8 | 9 | public class JDKTestProject extends Project { 10 | 11 | private final List subpackageBlacklist; 12 | private final List subpackageWhitelist; 13 | private final TestJobConfiguration jobConfiguration; 14 | 15 | public JDKTestProject() { 16 | this.subpackageBlacklist = null; 17 | this.subpackageWhitelist = null; 18 | this.jobConfiguration = null; 19 | } 20 | 21 | public JDKTestProject( 22 | String id, 23 | Product product, 24 | Set buildProviders, 25 | List subpackageBlacklist, 26 | List subpackageWhitelist, 27 | TestJobConfiguration jobConfiguration, 28 | List variables 29 | ) { 30 | super(id, product, ProjectType.JDK_TEST_PROJECT, buildProviders, variables); 31 | this.subpackageBlacklist = subpackageBlacklist; 32 | this.subpackageWhitelist = subpackageWhitelist; 33 | this.jobConfiguration = jobConfiguration; 34 | } 35 | 36 | public List getSubpackageBlacklist() { 37 | return subpackageBlacklist; 38 | } 39 | 40 | public List getSubpackageWhitelist() { 41 | return subpackageWhitelist; 42 | } 43 | 44 | public TestJobConfiguration getJobConfiguration() { 45 | return jobConfiguration; 46 | } 47 | 48 | @Override 49 | public boolean equals(Object o) { 50 | if (this == o) return true; 51 | if (!(o instanceof JDKTestProject)) return false; 52 | if (!super.equals(o)) return false; 53 | JDKTestProject that = (JDKTestProject) o; 54 | return Objects.equals(subpackageBlacklist, that.subpackageBlacklist) && 55 | Objects.equals(subpackageWhitelist, that.subpackageWhitelist) && 56 | Objects.equals(jobConfiguration, that.jobConfiguration); 57 | } 58 | 59 | @Override 60 | public int hashCode() { 61 | return Objects.hash(super.hashCode(), subpackageBlacklist, subpackageWhitelist, jobConfiguration); 62 | } 63 | 64 | @Override 65 | public String toString() { 66 | return "JDKTestProject{" + 67 | ", subpackageBlacklist='" + subpackageBlacklist + '\'' + 68 | ", subpackageWhitelist='" + subpackageWhitelist + '\'' + 69 | ", jobConfiguration=" + jobConfiguration + 70 | '}'; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /jenkins-scm-koji-plugin/src/main/java/hudson/plugins/scm/koji/BuildsSerializer.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.scm.koji; 2 | 3 | import hudson.plugins.scm.koji.model.Build; 4 | import hudson.plugins.scm.koji.model.RPM; 5 | import java.io.BufferedInputStream; 6 | import java.io.BufferedOutputStream; 7 | import java.io.File; 8 | import java.io.FileInputStream; 9 | import java.io.FileOutputStream; 10 | import java.io.InputStreamReader; 11 | import java.io.OutputStreamWriter; 12 | import java.io.Reader; 13 | import java.io.Writer; 14 | import java.lang.ref.SoftReference; 15 | import jakarta.xml.bind.JAXBContext; 16 | import jakarta.xml.bind.Marshaller; 17 | 18 | public class BuildsSerializer { 19 | 20 | private static SoftReference JAXB_CONTEXT_REFERENCE = new SoftReference<>(null); 21 | 22 | private static JAXBContext jaxbContext() { 23 | try { 24 | JAXBContext context = JAXB_CONTEXT_REFERENCE.get(); 25 | if (context == null) { 26 | context = JAXBContext.newInstance(Build.class, RPM.class); 27 | JAXB_CONTEXT_REFERENCE = new SoftReference<>(context); 28 | } 29 | return context; 30 | } catch (Exception ex) { 31 | throw new RuntimeException("Exception while initializing JAXB context", ex); 32 | } 33 | } 34 | 35 | public Build read(File file) { 36 | if (!file.exists() || !file.isFile() || file.length() < 1) { 37 | return null; 38 | } 39 | try (Reader reader = new InputStreamReader(new BufferedInputStream(new FileInputStream(file)), "UTF-8")) { 40 | Object result = jaxbContext().createUnmarshaller().unmarshal(reader); 41 | if (result == null || result instanceof Build) { 42 | return (Build) result; 43 | } 44 | // if we are still here - something went wrong: 45 | throw new RuntimeException("Deserialization expected Build but got: " + result); 46 | } catch (Exception ex) { 47 | throw new RuntimeException("Exception while reading the build XML", ex); 48 | } 49 | } 50 | 51 | public void write(Build build, File file) { 52 | try (Writer writer = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(file)), "UTF-8")) { 53 | Marshaller marshaller = jaxbContext().createMarshaller(); 54 | marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); 55 | marshaller.marshal(build, writer); 56 | } catch (Exception ex) { 57 | throw new RuntimeException("Exception while writing the build to file", ex); 58 | } 59 | } 60 | 61 | } 62 | --------------------------------------------------------------------------------