Posts

Showing posts from January, 2023

Share files between different agent workspace in the same Jenkins Pipeline via stash|unstash

Image
  Photo by  The Halal Design Studio  /  Unsplash I was working on a legacy app recently. The legacy app has angular as its frontend and spring boot app as its backend. Originally the frontend build outputs are committed in the app's git repository and packaged by spring boot by copying them to the  ${project.basedir}/target/classes/static/  class path(since content under the folder will be served as static resources by spring boot). And we are using Jenkins pipeline to run the build for this app. Hence the pipeline only use a java jenkins slave to compile and package the spring boot app. But that is not the right way, isn't it? We should run both build the pipeline for frontend angular app and backend sprint boot app. But an angular app required a node slave to build it out. We don't have a Jenkins slave that has both java and node installed. Then issue comes:  How to build java and javascript apps in a single Jenkins pipeline? Then I found Pipeline allows utilizing multipl

Swagger annotations for API that allows downloading files as zip

Image
  I have built out an API that allows you downloading log files as zip in a sprint boot app. The app also integrated with Swagger 3, so I also want this API can be hit in the Swagger UI. In this post, I will demonstrate how to use @ApiOperation annotation to tell Swagger UI download the response as a zip file. use @ApiOperation for your method The key is set media type to  "application/octet-stream"  which can be recognized by Swagger UI. By doing so, you are set "accept":" application/octet-stream " in the request header. Put below annotation section on top of your API's controller method. @Operation( summary = "", description = "", method="GET", responses = { @ApiResponse(responseCode = "200", description = "", content = { @Content( mediaType = "application/octet-stream"

How to Extract|Compress zip files using Java

  import  java.util.zip.ZipEntry; import  java.util.zip.ZipInputStream; import  java.util.zip.ZipOutputStream; extract Zip public class ZipExtract { public List<String> extractZipFile(MultipartFile zipFile) { try (val zipInput = new ZipInputStream(zipFile.getInputStream())) { List<String> logFiles = new ArrayList<>(); ZipEntry zipEntry; log.info("Received Zip File: {}", zipFile.getOriginalFilename()); while ((zipEntry = zipInput.getNextEntry()) != null) { log.info("Extracted Log File: {}", zipEntry.getName()); logFiles.add(IOUtils.toString(zipInput, StandardCharsets.UTF_8)); } return logFiles; } catch (IOException e) { log.error("Fail to extract the zip file!{}", zipFile.getOriginalFilename(), e); } return Collections.emptyList(); } } comprese Zip public class ZipCompress { pub

Resolved: Generate XSD or WSDL jaxb classes into multiple packages via maven-jaxb2-plugin

assume your app consumes multiple XSD or WSDL files from different vendors. You might want to generate the jaxb binding classes into separately packages per vendor's schema files. in this post, I will tell you 2 ways to do so. Use <generateDirectory>${project.build.directory}/generated-sources/xxx</generateDirectory> add multiple executions with different configuration. for each execution, you have to specify different generateDirectory, or it won't work. the below is a sample in pom.xml. <plugin> <groupId>org.jvnet.jaxb2.maven2</groupId> <artifactId>maven-jaxb2-plugin</artifactId> <version>0.14.0</version> <executions> <execution> <id>xxx-wsdl-generate</id> <goals> <goal>generate</goal> </goals> <configuration> <schemaLanguage>AUTODETECT</schemaLanguage>

ghost-storage-adapter-oracle-ords, A Oracle Cloud Autonomous JSON Databases storage adapter for Ghost 5.x

Image
npm install   ghost-storage-adapter-oracle-ords https://www.npmjs.com/package/ghost-storage-adapter-oracle-ords https://github.com/lengerrong/ghost-storage-adapter-oracle-ords#readme In my last post,  how to custom storage adapters to make your self-hosted Ghost instance filesystem completely external? , I had a plan to implement a storage adapter of Ghost for Oracle Cloud Autonomous JSON Databases to leverage the always free 40Gb space provided by Oracle Cloud. After researched Oracle ORDS REST API , I implement a orcal-ords-client lib to encapsulate the REST APIs for easy usage. Then I developed this storage adapter based on the  orcal-ords-client  lib. Core Idea The storage adapter is to save the images uploaded to Ghost into external rather than the file system where your Ghost instance deployed. I designed the below JSON document for a image: {   "path": "the unique path of the image, just consider the image is saved to local file system",   "blob":

oracle-ords-client, a javascript lib to persistent your Oracle Cloud Autonomous JSON Databases via Oracle ORDS Database Management REST API

oracle-ords-client oracle-ords-client is a JavaScript library that defines a simple and consistent abstraction for interacting with a Oracle Cloud Autonomous Databases via Oracle ORDS Database Management REST API. declare class OracleORDSClient implements ORDSOAuthClient { config: ORDSOAuthClientConfig; private access_token; private expires_at; constructor ( config: ORDSOAuthClientConfig ); putJSONDocument( alias: string , json: JSONValue ): Promise<Item>; deleteJSONObject( alias: string , id: string ): Promise<boolean>; queryJSONDocument( alias: string , query: any , payload: any ): Promise<Collection>; private buildUrl; private ensureOauthToken; } npm install oracle-ords-client https://www.npmjs.com/package/oracle-ords-client github home page https://github.com/lengerrong/oracle-ords-client Maximum JSONDocument size: 4.4M Usage Sample: https://github.com/lengerrong/oracle-ords-client/blob/main/lib/index.spec.ts References: Ho

cy.request with FormData and QueryString

correct FormData snippet please pass form: true and with the payload as body rather than use  FormData cy.request({ url, method: "post", headers: { Authorization: "Basic xxx", Accept: "*/*", "Cache-Control": "no-cache", "Accept-Encoding": "gzip, deflate, br" }, form: true, body: { "xxx":"yyy" } }).then((response) => {}) I tried create a  FormData  object and past it as body, but didn't work. correct QueryString snippet please pass qs with a JSON object rather than use  URLSearchParams cy.request({ url, method: "post", headers: { Authorization: `Bearer ${access_token}`, }, qs: { "parametername": "parametervalue" } }); I tried create a  URLSearchParams   object and past it as qs, but didn't work. cy.intercept won't work if the request not se