<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kengo TODA</title>
    <description>The latest articles on DEV Community by Kengo TODA (@kengotoda).</description>
    <link>https://dev.to/kengotoda</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F42477%2F17a1e3c8-9f2e-4848-a166-bbec8f0642cd.jpeg</url>
      <title>DEV Community: Kengo TODA</title>
      <link>https://dev.to/kengotoda</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kengotoda"/>
    <language>en</language>
    <item>
      <title>Use NodeJS v16 as runtime for JavaScript actions</title>
      <dc:creator>Kengo TODA</dc:creator>
      <pubDate>Wed, 29 Dec 2021 08:49:24 +0000</pubDate>
      <link>https://dev.to/kengotoda/use-nodejs-v16-as-runtime-for-javascript-actions-me5</link>
      <guid>https://dev.to/kengotoda/use-nodejs-v16-as-runtime-for-javascript-actions-me5</guid>
      <description>&lt;p&gt;This month &lt;a href="https://github.com/actions/runner/issues/772"&gt;GitHub supported NodeJS v16 as runtime for JavaScript actions&lt;/a&gt;. It is also &lt;a href="https://docs.github.com/en/enterprise-server@3.0/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-javascript-actions"&gt;supported by GitHub Enterprise Servers (GHES) 3.0&lt;/a&gt; and later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation to use NodeJS v16
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://nodejs.org/about/releases/"&gt;The end-of-life of NodeJS v12 is the end of next April&lt;/a&gt;. So, if you maintain your own JavaScript actions, it is suggested to migrate their runtime to NodeJS v16.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to update the project
&lt;/h2&gt;

&lt;p&gt;We can complete the minimal migration by &lt;a href="https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-javascript-actions"&gt;updating &lt;code&gt;run.using&lt;/code&gt; in the &lt;code&gt;actions.yml&lt;/code&gt; file&lt;/a&gt;. We may need several additional updates like below:&lt;/p&gt;

&lt;h3&gt;
  
  
  Update &lt;code&gt;engines.node&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;If you have specified the version of NodeJS to use in &lt;code&gt;package.json&lt;/code&gt;, you will need to update it.&lt;br&gt;
&lt;code&gt;16.13.1&lt;/code&gt; is the current latest version, so the preferred configuration would be as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"engines"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^16.13.1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update &lt;code&gt;tsconfig.json&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;NodeJS v16 lets us use ES2021. Based on the &lt;a href="https://github.com/microsoft/TypeScript/wiki/Node-Target-Mapping#node-16"&gt;official TSConfig settings recommendation for NodeJS v16&lt;/a&gt;, update the &lt;code&gt;compilerOptions&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lib"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"ES2021"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"commonjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ES2021"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update TypeScript
&lt;/h3&gt;

&lt;p&gt;If your TypeScript is too old to use ES2021, it is suggested to update.&lt;/p&gt;

&lt;p&gt;Note that TypeScript v4.4 &lt;a href="https://devblogs.microsoft.com/typescript/announcing-typescript-4-4/#use-unknown-catch-variables"&gt;changed the type of caught error from &lt;code&gt;any&lt;/code&gt; to &lt;code&gt;unknown&lt;/code&gt; by default&lt;/a&gt;.&lt;br&gt;
So if your action catches error to invoke &lt;code&gt;core.setFailed()&lt;/code&gt; method, you need to check the type of caught object in runtime:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-     core.setFailed(error)
&lt;/span&gt;&lt;span class="gi"&gt;+     if (error instanceof Error) {
+       core.setFailed(error)
+     } else {
+       core.setFailed(JSON.stringify(error))
+     }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update ESLint
&lt;/h3&gt;

&lt;p&gt;If you've updated your TypeScript, it is necessary to update ESLint too. If you've created projects based on the &lt;a href="https://github.com/actions/typescript-action"&gt;official template project&lt;/a&gt;, you can run the following command to upgrade ESLint and its plugins in batch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm add &lt;span class="nt"&gt;-D&lt;/span&gt; eslint@^8.5.0 @typescript-eslint/parser@^5.8.0 eslint-plugin-github@^4.3.5 eslint-plugin-jest@^25.3.0 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you found lint failure caused by changes on the ESLint side, copy the &lt;a href="https://github.com/actions/typescript-action/blob/56d91620d7eacab6e7d3498bb7c114285476688e/.eslintrc.json"&gt;default &lt;code&gt;.eslintrc.json&lt;/code&gt; from the template project&lt;/a&gt;, or follow ESLint's migration guide documented in its &lt;a href="https://github.com/typescript-eslint/typescript-eslint/releases"&gt;GitHub Releases&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update GitHub Actions Workflow to use NodeJS v16
&lt;/h3&gt;

&lt;p&gt;If you use the default NodeJS on the PATH, you need no action because &lt;a href="https://github.blog/changelog/2021-12-10-github-actions-github-hosted-runners-now-run-node-js-16-by-default/"&gt;GitHub hosted runners use NodeJS v16 by default since this Dec/10th&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you use &lt;code&gt;actions/setup-node&lt;/code&gt; to specify the version of NodeJS, you need to update the &lt;code&gt;node-version&lt;/code&gt; config in the workflow definitions.&lt;br&gt;&lt;br&gt;
Or if you have a configuration file like &lt;code&gt;.node-version&lt;/code&gt; and &lt;code&gt;.nvmrc&lt;/code&gt;, you can use the &lt;a href="https://github.com/actions/setup-node/releases/tag/v2.5.0"&gt;&lt;code&gt;node-version-file&lt;/code&gt; config supported from &lt;code&gt;v2.5.0&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;NodeJS v12 will reach its end-of-life soon. All system running on NodeJS needs to be migrated, and GitHub JavaScript Actions are also in the target.&lt;/p&gt;

&lt;p&gt;The migration process is quite simple, just update metadata and run the build with NodeJS v16. You may refer to &lt;a href="https://github.com/gradle/wrapper-validation-action/pull/53"&gt;my PR for gradle/wrapper-validation-action&lt;/a&gt; as example. Enjoy!&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>github</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>SpotBugs supports SARIF that helps integration with other SAST tools</title>
      <dc:creator>Kengo TODA</dc:creator>
      <pubDate>Sun, 17 Oct 2021 02:17:53 +0000</pubDate>
      <link>https://dev.to/kengotoda/spotbugs-supports-sarif-that-supports-integration-with-other-sast-tools-5fn</link>
      <guid>https://dev.to/kengotoda/spotbugs-supports-sarif-that-supports-integration-with-other-sast-tools-5fn</guid>
      <description>&lt;p&gt;Are you using SAST tools? How many tools you're using? Just one? Then it's fine. A few? It's still working, probably. More? Welcome to one of difficulties of DevSecOps!&lt;/p&gt;

&lt;p&gt;Currently, when we maintain a system, it's quite common to depend on multiple languages and ecosystems. If system is enough small, a one-stop SAST solution should be enough... but later you may find it's not enough.&lt;/p&gt;

&lt;p&gt;Then how to integrate reports generated by multiple SAST tools, to grab the overview of your system? The &lt;a href="https://sarifweb.azurewebsites.net/"&gt;Static Analysis Results Interchange Format (SARIF)&lt;/a&gt; could be a solution.&lt;/p&gt;

&lt;p&gt;SARIF is an OASIS standard and an industry standard format for the output of static analysis tools. Configure each SAST tool to generate a SARIF report, then we can merge reports to get a simple overview of the service. The &lt;a href="https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning"&gt;GitHub Code scanning&lt;/a&gt; is one example, it works as a dashboard of all SAST tools like below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--os1UN5r1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5g3d8101gtyv4q7as4rs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--os1UN5r1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5g3d8101gtyv4q7as4rs.png" alt="GitHub Code scanning Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to configure SpotBugs to generate a SARIF report
&lt;/h2&gt;

&lt;p&gt;First, it's better to use SpotBugs 4.4.1 and above, that includes a &lt;a href="https://github.com/spotbugs/spotbugs/issues/1630"&gt;fix to make SARIF report compatible with Github code scanning API requirements&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you use command line interface to run SpotBugs, append &lt;a href="https://spotbugs.readthedocs.io/en/latest/running.html?highlight=sarif#text-ui-options"&gt;&lt;code&gt;-sarif&lt;/code&gt; option&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are using Gradle, configure tasks with &lt;code&gt;SpotBugsTask&lt;/code&gt; to set &lt;code&gt;reports.sarif.enabled&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;spotbugsMain&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;reports&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;sarif&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are using Maven, configure the plugin with &lt;code&gt;&amp;lt;sarifOutput&amp;gt;true&amp;lt;/sarifOutput&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;      &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.github.spotbugs&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spotbugs-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;sarifOutput&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/sarifOutput&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Refer to &lt;a href="https://github.com/spotbugs/spotbugs-gradle-plugin"&gt;spotbugs/spotbugs-gradle-plugin&lt;/a&gt; as a living example with GitHub Code scanning integration.&lt;/p&gt;

&lt;p&gt;Hope that this guide helps you to find new way to handle SAST tool reports, and make your hacking awesome!&lt;/p&gt;

</description>
      <category>sast</category>
      <category>devsecops</category>
      <category>spotbugs</category>
      <category>java</category>
    </item>
    <item>
      <title>How to replace @types/jest with @jest/globals and jest-mock</title>
      <dc:creator>Kengo TODA</dc:creator>
      <pubDate>Sun, 22 Aug 2021 09:38:31 +0000</pubDate>
      <link>https://dev.to/kengotoda/how-to-replace-types-jest-with-jest-globals-and-jest-mock-52mb</link>
      <guid>https://dev.to/kengotoda/how-to-replace-types-jest-with-jest-globals-and-jest-mock-52mb</guid>
      <description>&lt;p&gt;I believe that it's always better to prefer official type definitions rather than unofficial DefinitelyTyped. And &lt;a href="https://jestjs.io/ja/blog/2021/05/25/jest-27"&gt;Jest v27 introduced new defaults&lt;/a&gt; so I thought that it's a nice timing to replace &lt;code&gt;@types/jest&lt;/code&gt; with &lt;code&gt;@jest/globals&lt;/code&gt; and &lt;code&gt;jest-mock&lt;/code&gt;. I'll share several problems I met:&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependency Update
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;jest-circus&lt;/code&gt; is now default test runner, so we don't need to depend on it directly. Also remove &lt;code&gt;@types/jest&lt;/code&gt; to replace with &lt;code&gt;@jest/globals&lt;/code&gt; and &lt;code&gt;jest-mock&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm remove jest-circus @types/jest
npm add &lt;span class="nt"&gt;-D&lt;/span&gt; jest@^27.0.6 ts-jest@^27.0.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;I'm using &lt;code&gt;ts-jest&lt;/code&gt; to transpile TypeScript code, and its configuration is like below. Now we can remove both &lt;code&gt;testEnvironment&lt;/code&gt; and &lt;code&gt;testRunner&lt;/code&gt; in most cases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tsjPreset&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ts-jest/presets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;clearMocks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;moduleFileExtensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;// no need `testEnvironment: "node"` any more&lt;/span&gt;
  &lt;span class="na"&gt;testMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;**/*.test.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;// no need `testRunner: "jest-circus"` any more&lt;/span&gt;
  &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;tsjPreset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;verbose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I &lt;a href="https://kulshekhar.github.io/ts-jest/docs/getting-started/presets#advanced"&gt;do not use preset to configure &lt;code&gt;ts-jest&lt;/code&gt;&lt;/a&gt;, to let other integrations like puppeteer use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Import from &lt;code&gt;@jest/globals&lt;/code&gt; and &lt;code&gt;jest-mock&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;As described in the &lt;a href="https://jestjs.io/docs/api"&gt;official API Document&lt;/a&gt;, we can import Jest API from &lt;code&gt;@jest/globals&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;About &lt;code&gt;SpyInstance&lt;/code&gt;, &lt;code&gt;@types/jest&lt;/code&gt; provides it as &lt;code&gt;jest.SpyInstance&lt;/code&gt;. But official type definition provides it as &lt;code&gt;import { SpyInstance } from 'jest-mock';&lt;/code&gt; ... with generics!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@jest/globals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SpyInstance&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jest-mock&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;spyOSHomedir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SpyInstance&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;spyOSHomedir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;homedir&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;spyOSHomedir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mockReturnValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generics will bring better type safety, and tons of code change. For instance, mocked function sometimes wants to return the value that satisfies required type partially. In the following case, mocked &lt;code&gt;fs.statSync&lt;/code&gt; returns an object that has only &lt;code&gt;isFile()&lt;/code&gt; method even though the &lt;a href="https://nodejs.org/docs/latest-v12.x/api/fs.html#fs_class_fs_stats"&gt;required type &lt;code&gt;fs.Stats&lt;/code&gt; has more properties and methods&lt;/a&gt;. In such case we can use the &lt;a href="https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype"&gt;Partial utility type&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@jest/globals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SpyInstance&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jest-mock&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;spyFsStat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SpyInstance&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stats&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BigIntStats&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PathLike&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatOptions&lt;/span&gt;&lt;span class="p"&gt;?]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;spyFsStat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;statSync&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;spyFsStat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mockImplementation&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PathLike&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;expectedJdkFile&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One more example: when you mock overloaded methods, you'll face some difficulty like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://javascript.plainenglish.io/mocking-ts-method-overloads-with-jest-e9c3d3f1ce0c"&gt;https://javascript.plainenglish.io/mocking-ts-method-overloads-with-jest-e9c3d3f1ce0c&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By applying the solution introduced in that article, we may lose integrity in test codes. So it would be an acceptable solution to use &lt;code&gt;unknown&lt;/code&gt; in some cases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;spyFsReadDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SpyInstance&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Parameters&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readdirSync&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// returned value is typed as `Dirent[]` but we want to return `string[]`, so use `unknown` to relax mismatch&lt;/span&gt;
  &lt;span class="nx"&gt;spyFsReadDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;readdirSync&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;spyFsReadDir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mockImplementation&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;JavaTest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all, you may refer to &lt;a href="https://github.com/KengoTODA/setup-java/commit/24f091afd1eab070d0107b0ac233a5f4cc77aef5"&gt;my commit&lt;/a&gt; replacing DefinitelyTyped with official type definitions. Thank you!&lt;/p&gt;

</description>
      <category>jest</category>
      <category>typescript</category>
    </item>
    <item>
      <title>A complete guide to use dependabot with semantic-release and @vercel/ncc for GitHub Actions</title>
      <dc:creator>Kengo TODA</dc:creator>
      <pubDate>Fri, 16 Jul 2021 12:05:34 +0000</pubDate>
      <link>https://dev.to/kengotoda/a-complete-guide-to-use-dependabot-with-semantic-release-and-vercel-ncc-for-github-actions-230p</link>
      <guid>https://dev.to/kengotoda/a-complete-guide-to-use-dependabot-with-semantic-release-and-vercel-ncc-for-github-actions-230p</guid>
      <description>&lt;p&gt;&lt;a href="https://dependabot.com/" rel="noopener noreferrer"&gt;Depandabot&lt;/a&gt; is a really productive solution to keep our products secure and updated.&lt;/p&gt;

&lt;p&gt;It is also easy to set up, however, it provides no chance to run a command in the PR, so we have additional considerations if we have some pre-release processes. For instance, for a GitHub Actions repository, we want to keep the &lt;code&gt;dist&lt;/code&gt; directory updated by &lt;a href="https://www.npmjs.com/package/@vercel/ncc" rel="noopener noreferrer"&gt;&lt;code&gt;@vercel/ncc&lt;/code&gt;&lt;/a&gt; right after we update its dependencies.&lt;/p&gt;

&lt;p&gt;This article introduces &lt;a href="https://semantic-release.gitbook.io/" rel="noopener noreferrer"&gt;semantic-release&lt;/a&gt; as a solution. It automates the release process, and its &lt;a href="https://github.com/semantic-release/exec" rel="noopener noreferrer"&gt;exec plugin&lt;/a&gt; helps us to run &lt;code&gt;@vercel/ncc&lt;/code&gt; before the release automatically.&lt;/p&gt;

&lt;p&gt;Overview of the development process is like below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dependabot creates a PR to update dependencies&lt;/li&gt;
&lt;li&gt;GitHub Actions test the change, and reflect its result to GitHub Checks&lt;/li&gt;
&lt;li&gt;Merge the PR manually or automatically&lt;/li&gt;
&lt;li&gt;GitHub Actions run on the default branch, and trigger the semantic-release&lt;/li&gt;
&lt;li&gt;semantic-release creates a Git tag, a GitHub Release, and a npm release&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Check the following chapters for detail, or refer to &lt;a href="https://github.com/KengoTODA/actions-setup-docker-compose/tree/ce91d5b76f4c9910e6958b58396df65e8fdaebe0" rel="noopener noreferrer"&gt;my GitHub repo&lt;/a&gt; as a working example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install necessary node packages
&lt;/h2&gt;

&lt;p&gt;Make sure you have a npm project in your working directory, and run the following command to install semantic-release and its plugins:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm add &lt;span class="nt"&gt;-D&lt;/span&gt; semantic-release @semantic-release/exec @semantic-release/git 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Configure npm to run &lt;code&gt;@vercel/ncc&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;package.json&lt;/code&gt;, confirm that we have a script to run &lt;code&gt;ncc&lt;/code&gt; to optimize JS files like below:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"package"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ncc build --source-map"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Configure semantic-release
&lt;/h2&gt;

&lt;p&gt;Follow the &lt;a href="https://semantic-release.gitbook.io/semantic-release/usage/configuration" rel="noopener noreferrer"&gt;official documents&lt;/a&gt; to configure &lt;code&gt;semantic-release&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In my case, it became like below to use the &lt;code&gt;main&lt;/code&gt; branch as default branch, and run &lt;code&gt;exec&lt;/code&gt; plugin and &lt;code&gt;git&lt;/code&gt; plugin:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"release"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"branches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"@semantic-release/commit-analyzer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"@semantic-release/release-notes-generator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"@semantic-release/npm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"@semantic-release/github"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"@semantic-release/exec"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"prepare"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run package"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"@semantic-release/git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"assets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"dist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"package.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"package-lock.json"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"chore(release): ${nextRelease.version} [skip ci]&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;${nextRelease.notes}"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Configure the dependabot to follow the Conventional Commit
&lt;/h2&gt;

&lt;p&gt;Configure &lt;code&gt;.github/dependabot.yml&lt;/code&gt; to enable dependabot. Make sure &lt;code&gt;commit-message&lt;/code&gt; part is configured with &lt;code&gt;prefix: fix&lt;/code&gt; to following the &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/" rel="noopener noreferrer"&gt;Conventional Commits&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="na"&gt;updates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;package-ecosystem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm&lt;/span&gt;
    &lt;span class="na"&gt;directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/"&lt;/span&gt;
    &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;daily&lt;/span&gt;
    &lt;span class="na"&gt;commit-message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fix&lt;/span&gt;
      &lt;span class="na"&gt;prefix-development&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chore&lt;/span&gt;
      &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;scope&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  (optional) Configure the auto-merge probot
&lt;/h2&gt;

&lt;p&gt;To merge PRs made by dependabot automatic, you may introduce &lt;a href="https://github.com/apps/probot-auto-merge" rel="noopener noreferrer"&gt;probot-auto-merge&lt;/a&gt;. &lt;code&gt;.github/auto-merge.yml&lt;/code&gt; will be like below:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;minApprovals&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;NONE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="na"&gt;requiredLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;dependencies&lt;/span&gt;
&lt;span class="na"&gt;updateBranch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;mergeMethod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rebase&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If we apply &lt;code&gt;NONE: 0&lt;/code&gt; to &lt;code&gt;minApprovals&lt;/code&gt; configuration to merge without manual review, make sure the &lt;a href="https://docs.github.com/en/github/administering-a-repository/defining-the-mergeability-of-pull-requests/about-protected-branches" rel="noopener noreferrer"&gt;branch protection rule&lt;/a&gt; is created for the default branch, to make sure PRs will be merged only when &lt;a href="https://docs.github.com/en/github/administering-a-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks" rel="noopener noreferrer"&gt;required status checks&lt;/a&gt; have passed.&lt;/p&gt;

&lt;p&gt;There is no way to configure the branch protection rule by file, so you need to use GUI at github.com like below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbgsgwmhgn5y26m77fhl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbgsgwmhgn5y26m77fhl.png" alt="screenshot of the branch protection rule GUI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a PAT (Personal Access Token)
&lt;/h2&gt;

&lt;p&gt;semantic-release needs a GitHub token to push a commit. But when we have branch protection rules for the target branch, &lt;code&gt;secrets.GITHUB_TOKEN&lt;/code&gt; provides not enough permission so you'll face an &lt;a href="https://github.com/KengoTODA/actions-setup-docker-compose/runs/3085079041?check_suite_focus=true#step:6:2121" rel="noopener noreferrer"&gt;error like below&lt;/a&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

error: GH006: Protected branch update failed for refs/heads/main.
error: 2 of 2 required status checks are expected.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To avoid this error, &lt;a href="https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token" rel="noopener noreferrer"&gt;create a PAT&lt;/a&gt; and store it as an &lt;a href="https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository" rel="noopener noreferrer"&gt;encrypted secret&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To keep our development environment secure, it's better to keep &lt;a href="https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps" rel="noopener noreferrer"&gt;PAT's scope&lt;/a&gt; minimal as much as possible. In my case, just a &lt;code&gt;public_repo&lt;/code&gt; scope is enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure GitHub Actions
&lt;/h2&gt;

&lt;p&gt;We have a PAT so now we can configure GitHub Actions workflow!&lt;br&gt;
It'll be like below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="c1"&gt;# Make sure the release step uses its own credentials.&lt;/span&gt;
          &lt;span class="na"&gt;persist-credentials&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;npm ci&lt;/span&gt;
          &lt;span class="s"&gt;npm run all&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run semantic-release&lt;/span&gt;
        &lt;span class="c1"&gt;# This process will run `ncc`, commit files, push a Git commit, and release to GitHub and npmjs.&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;npx semantic-release&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.PAT_TO_PUSH }}&lt;/span&gt;
          &lt;span class="na"&gt;NPM_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.NPM_TOKEN }}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Or you may refer to &lt;a href="https://github.com/KengoTODA/actions-setup-docker-compose/blob/ce91d5b76f4c9910e6958b58396df65e8fdaebe0/.github/workflows/test.yml" rel="noopener noreferrer"&gt;my workflow config&lt;/a&gt; as a working example.&lt;/p&gt;

&lt;p&gt;Important points are as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;actions/checkout&lt;/code&gt; with &lt;code&gt;persist-credentials: false&lt;/code&gt;, or &lt;a href="https://github.com/semantic-release/git/issues/196#issuecomment-601310576" rel="noopener noreferrer"&gt;&lt;code&gt;git&lt;/code&gt; plugin will use the GitHub token generated by &lt;code&gt;actions/checkout&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Set the PAT created at the previous chapter to &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; when we run &lt;code&gt;npx semantic-release&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;Dependabot is really productive, even to GitHub Actions project that needs to keep the &lt;code&gt;dist&lt;/code&gt; directory updated. semantic-release helps us not only by tagging but also by running commands to make the project ready to release.&lt;/p&gt;

&lt;p&gt;There are several pitfalls around permission control, hope that this article helps you to avoid them. Enjoy hacking! :)&lt;/p&gt;

</description>
      <category>semanticrelease</category>
      <category>githubactions</category>
      <category>dependabot</category>
    </item>
    <item>
      <title>New GitHub Action to set up docker-compose</title>
      <dc:creator>Kengo TODA</dc:creator>
      <pubDate>Fri, 28 Aug 2020 12:23:36 +0000</pubDate>
      <link>https://dev.to/kengotoda/new-github-action-to-set-up-docker-compose-4ne3</link>
      <guid>https://dev.to/kengotoda/new-github-action-to-set-up-docker-compose-4ne3</guid>
      <description>&lt;h3&gt;
  
  
  My Action
&lt;/h3&gt;

&lt;p&gt;This &lt;a href="https://github.com/KengoTODA/actions-setup-docker-compose"&gt;setup-docker-compose action&lt;/a&gt; downloads the &lt;code&gt;docker-compose&lt;/code&gt; command and add it to the &lt;code&gt;PATH&lt;/code&gt; for following executions. At this moment, It supports the Linux environment only.&lt;/p&gt;

&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Wacky Wildcards. Usually, FOSS projects don't need to use this action, because action runners hosted by GitHub already have &lt;code&gt;docker-compose&lt;/code&gt; in its &lt;code&gt;PATH&lt;/code&gt;. So other categories aren't suitable to submit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Yaml File or Link to Code
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/KengoTODA"&gt;
        KengoTODA
      &lt;/a&gt; / &lt;a href="https://github.com/KengoTODA/actions-setup-docker-compose"&gt;
        actions-setup-docker-compose
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      the GitHub Action setting up docker-compose command
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
GitHub action to setup &lt;code&gt;docker-compose&lt;/code&gt; command&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://github.com/KengoTODA/actions-setup-docker-compose/actions"&gt;&lt;img alt="actions-setup-docker-compose status" src="https://res.cloudinary.com/practicaldev/image/fetch/s--CkeA2QE1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/KengoTODA/actions-setup-docker-compose/workflows/build-test/badge.svg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This action downloads the &lt;code&gt;docker-compose&lt;/code&gt; command and add it to the &lt;code&gt;PATH&lt;/code&gt; for following execution. It supports Linux environment only.&lt;/p&gt;
&lt;h2&gt;
How to use&lt;/h2&gt;
&lt;p&gt;Add a step to your workflow like below:&lt;/p&gt;
&lt;div class="highlight highlight-source-yaml"&gt;&lt;pre&gt;  &lt;span class="pl-ent"&gt;steps&lt;/span&gt;:
  - &lt;span class="pl-ent"&gt;uses&lt;/span&gt;: &lt;span class="pl-s"&gt;KengoTODA/actions-setup-docker-compose@main&lt;/span&gt;
    &lt;span class="pl-ent"&gt;with&lt;/span&gt;:
      &lt;span class="pl-ent"&gt;version&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;1.26.2&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;version&lt;/code&gt; parameter is required, specify the full version of &lt;code&gt;docker-compose&lt;/code&gt; command.&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/KengoTODA/actions-setup-docker-compose"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  Additional Resources / Info
&lt;/h3&gt;

&lt;p&gt;As noted above, FOSS projects usually don't need to use this action. So there is no FOSS project depending on it for now.&lt;/p&gt;

&lt;p&gt;This action is for who's trying to integrate FOSS power into in-house development with the self-hosted runner.&lt;/p&gt;

</description>
      <category>actionshackathon</category>
      <category>github</category>
      <category>opensource</category>
      <category>dockercompose</category>
    </item>
    <item>
      <title>Deploying to OSSRH with Gradle in 2020</title>
      <dc:creator>Kengo TODA</dc:creator>
      <pubDate>Wed, 29 Apr 2020 01:22:29 +0000</pubDate>
      <link>https://dev.to/kengotoda/deploying-to-ossrh-with-gradle-in-2020-1lhi</link>
      <guid>https://dev.to/kengotoda/deploying-to-ossrh-with-gradle-in-2020-1lhi</guid>
      <description>&lt;p&gt;It seems that the method described in &lt;a href="https://central.sonatype.org/pages/gradle.html"&gt;the official page&lt;/a&gt; is a little bit old. Here I'll introduce a modern way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metadata and Signing
&lt;/h2&gt;

&lt;p&gt;Use &lt;a href="https://docs.gradle.org/current/userguide/publishing_maven.html#publishing_maven"&gt;the &lt;code&gt;maven-publish&lt;/code&gt; plugin&lt;/a&gt; instead of &lt;a href="https://docs.gradle.org/current/userguide/maven_plugin.html"&gt;the &lt;code&gt;maven&lt;/code&gt; plugin&lt;/a&gt;. No need to configure the &lt;code&gt;artifacts&lt;/code&gt; extension.&lt;/p&gt;

&lt;h2&gt;
  
  
  Jar Files
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;classifier&lt;/code&gt; property of &lt;code&gt;Jar&lt;/code&gt; task is now &lt;a href="https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html#org.gradle.api.tasks.bundling.Jar:classifier"&gt;deprecated&lt;/a&gt;. Instead, we can use &lt;a href="https://docs.gradle.org/current/userguide/java_plugin.html#sec:java-extension"&gt;&lt;code&gt;withJavadocJar()&lt;/code&gt; and &lt;code&gt;withSourcesJar()&lt;/code&gt; in the &lt;code&gt;java&lt;/code&gt; extension&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;withJavadocJar&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;withSourcesJar&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Signing artifacts
&lt;/h2&gt;

&lt;p&gt;We're using &lt;code&gt;maven-publish&lt;/code&gt; plugin, so the &lt;code&gt;signing&lt;/code&gt; extension in our build script will be like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isReleaseVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;endsWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"SNAPSHOT"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// -------------------------------------&lt;/span&gt;
&lt;span class="c1"&gt;// here 'publishing' extension will come&lt;/span&gt;
&lt;span class="c1"&gt;// -------------------------------------&lt;/span&gt;

&lt;span class="n"&gt;signing&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;sign&lt;/span&gt; &lt;span class="n"&gt;publishing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;publications&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mavenJava&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Sign&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;onlyIf&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;isReleaseVersion&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Metadata Definition and Upload
&lt;/h2&gt;

&lt;p&gt;Instead of &lt;code&gt;uploadArchives&lt;/code&gt; extension for the &lt;code&gt;maven&lt;/code&gt; plugin, configure &lt;code&gt;publishing&lt;/code&gt; extension for the &lt;code&gt;maven-publish&lt;/code&gt; plugin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;publishing&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;repositories&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;maven&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;releaseRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://oss.sonatype.org/service/local/staging/deploy/maven2/"&lt;/span&gt;
            &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;snapshotRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://oss.sonatype.org/content/repositories/snapshots/"&lt;/span&gt;
            &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;isReleaseVersion&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;releaseRepo&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;snapshotRepo&lt;/span&gt;
            &lt;span class="n"&gt;credentials&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ossrhUsername'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;ossrhUsername&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Unknown user"&lt;/span&gt;
                &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ossrhPassword'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;ossrhPassword&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Unknown password"&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;publications&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;mavenJava&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MavenPublication&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;pom&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;groupId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'com.example'&lt;/span&gt;
                &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'example project'&lt;/span&gt;
                &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Example Project to learn how to deploy to OSSRH'&lt;/span&gt;
                &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'https://example.com/'&lt;/span&gt;
                &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;
                &lt;span class="n"&gt;licenses&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;license&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'The Apache License, Version 2.0'&lt;/span&gt;
                        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'http://www.apache.org/licenses/LICENSE-2.0.txt'&lt;/span&gt;
                    &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="n"&gt;scm&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'scm:git:git@github.com:example.com/example.git'&lt;/span&gt;
                    &lt;span class="n"&gt;developerConnection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'scm:git:git@github.com:example.com/example.git'&lt;/span&gt;
                    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'https://github.com/example.com/example/'&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;Use the &lt;code&gt;publishToMavenLocal&lt;/code&gt; task to publish artifacts to maven local repository.&lt;/p&gt;

&lt;p&gt;Use the &lt;code&gt;publish&lt;/code&gt; task to publish artifacts to maven remote repositories. Don't forget to visit &lt;a href="https://oss.sonatype.org/"&gt;oss.sonatype.org&lt;/a&gt; to close and release your staging repository.&lt;/p&gt;

</description>
      <category>java</category>
      <category>gradle</category>
    </item>
    <item>
      <title>SpotBugs v4.0.0 is out!</title>
      <dc:creator>Kengo TODA</dc:creator>
      <pubDate>Wed, 19 Feb 2020 11:04:58 +0000</pubDate>
      <link>https://dev.to/kengotoda/spotbugs-v4-0-0-is-out-32ej</link>
      <guid>https://dev.to/kengotoda/spotbugs-v4-0-0-is-out-32ej</guid>
      <description>&lt;p&gt;This week we've released &lt;a href="https://github.com/spotbugs/spotbugs/blob/4.0.0/CHANGELOG.md#400---2020-02-15"&gt;SpotBugs v4.0.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HaZB-YAa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spotbugs.github.io/images/logos/spotbugs_logo_600px.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HaZB-YAa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spotbugs.github.io/images/logos/spotbugs_logo_600px.png" alt="SpotBugs Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We've spent about a year to deliver this stable version, however, this version has less breaking changes. We removed only unused features based on &lt;a href="https://github.com/spotbugs/discuss/issues/65"&gt;this investigation&lt;/a&gt;. I wish you can enjoy the new version with fewer migration costs.&lt;/p&gt;

&lt;p&gt;Note that default detectors in this version still has some problems around Java 9+, check &lt;a href="https://github.com/spotbugs/spotbugs/issues?q=is%3Aopen+is%3Aissue+label%3AJava-9"&gt;related issues&lt;/a&gt; if you run SpotBugs for projects using Java 11, 14 or later. To avoid this problem, you can &lt;a href="https://spotbugs.readthedocs.io/en/latest/running.html#detector-visitor-configuration-options"&gt;limit activated detectors by command line option&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We also provide &lt;a href="https://spotbugs.readthedocs.io/en/stable/migration.html#guide-for-migration-from-spotbugs-3-1-to-4-0"&gt;the official migration guide&lt;/a&gt;. If you're SpotBugs plugin author, please check it to ease your migration.&lt;/p&gt;

&lt;p&gt;BTW if you're using IntelliJ IDEA, watch &lt;a href="https://github.com/spotbugs/spotbugs/issues/515"&gt;this issue&lt;/a&gt; and contribute to help &lt;a href="https://github.com/GoSecure/findbugs-idea"&gt;the SpotBugs-IDEA project&lt;/a&gt;. I'm not member of it, but it seems pretty cool.&lt;br&gt;
And if you're using Gradle, watch &lt;a href="https://github.com/spotbugs/spotbugs-gradle-plugin/issues/180"&gt;this issue&lt;/a&gt; and help us to verify &lt;a href="https://github.com/KengoTODA/spotbugs-gradle-plugin-v2/"&gt;the experimental implementation&lt;/a&gt;. Current implementation has many problems, and it's quite hard to solve incrementally, so I started this project from scratch. It seems working and keep most of API, but we still need your contribution especially from &lt;a href="https://github.com/KengoTODA/spotbugs-gradle-plugin-v2/issues/1"&gt;Android project developers&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>spotbugs</category>
      <category>java</category>
    </item>
    <item>
      <title>Tips to implement Gradle Plugin</title>
      <dc:creator>Kengo TODA</dc:creator>
      <pubDate>Thu, 09 Jan 2020 20:59:13 +0000</pubDate>
      <link>https://dev.to/kengotoda/tips-to-implement-gradle-plugin-8d6</link>
      <guid>https://dev.to/kengotoda/tips-to-implement-gradle-plugin-8d6</guid>
      <description>&lt;p&gt;Now I'm implementing &lt;a href="https://github.com/KengoTODA/spotbugs-gradle-plugin-v2"&gt;a new Gradle Plugin&lt;/a&gt;. &lt;a href="https://gradle.org/guides/?q=Plugin%20Development"&gt;The official document&lt;/a&gt; is really nice, and I wish my experience will help you to code yours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use groovy for extension and task
&lt;/h2&gt;

&lt;p&gt;The extension is a major way to configure your plugin. It's a class that uses &lt;a href="https://docs.gradle.org/current/userguide/lazy_configuration.html"&gt;Property and Provider&lt;/a&gt; as its fields, then users can set values like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;extension&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;intProp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
  &lt;span class="n"&gt;fileProp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'config.yml'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;listProp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'bar'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'baz'&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; 
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Groovy helps you to generate necessary accessors, so what you need is simply private final fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyExtension&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@NonNull&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Property&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;boolProp&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="n"&gt;MyExtension&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ObjectFactory&lt;/span&gt; &lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;boolProp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;convention&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyTask&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;DefaultTask&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Input&lt;/span&gt;
    &lt;span class="nd"&gt;@NonNull&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Property&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;boolProp&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="n"&gt;MyTask&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ObjectFactory&lt;/span&gt; &lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;extension&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exntensions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getByType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyExtension&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;boolProp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;convention&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;extension&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;boolProp&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Always prefer lazy-approach
&lt;/h2&gt;

&lt;p&gt;For better performance, we need to learn about &lt;a href="https://docs.gradle.org/current/userguide/build_lifecycle.html"&gt;build lifecycle&lt;/a&gt;, or face performance problem like &lt;a href="https://github.com/spotbugs/spotbugs-gradle-plugin/issues/165"&gt;this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Prefer the lazy-approach. Pick APIs that lets you specify a &lt;code&gt;configurationAction&lt;/code&gt; as its parameter like &lt;a href="https://docs.gradle.org/6.0.1/javadoc/org/gradle/api/tasks/TaskContainer.html#register-java.lang.String-java.lang.Class-org.gradle.api.Action-"&gt;TaskContainer#register(...)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Refer &lt;a href="https://docs.gradle.org/current/userguide/task_configuration_avoidance.html"&gt;the official document&lt;/a&gt; for detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand the difference between getXxx() and findXxx()
&lt;/h2&gt;

&lt;p&gt;In Groovy modules, methods named &lt;code&gt;getXxx()&lt;/code&gt; throw an exception if you found nothing. On the other hand, methods named &lt;code&gt;findXxx()&lt;/code&gt; return &lt;code&gt;null&lt;/code&gt; (not &lt;code&gt;Optional&lt;/code&gt;!).&lt;/p&gt;

&lt;p&gt;So when you expect that you always find the value (e.g. get the extension created by your plugin), use &lt;code&gt;getXxx()&lt;/code&gt;. Otherwise, prefer &lt;code&gt;findXxx()&lt;/code&gt; and check the nullness of returned value.&lt;/p&gt;

&lt;h1&gt;
  
  
  Worker API
&lt;/h1&gt;

&lt;p&gt;To run heavy computations like static analysis, it is better to use &lt;a href="https://guides.gradle.org/using-the-worker-api/"&gt;the Gradle Worker API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In my case, I need to launch a JVM process to kick &lt;a href="https://spotbugs.github.io/"&gt;SpotBugs&lt;/a&gt;, and it makes build especially in multi-module projects. Here is the result of &lt;a href="https://github.com/KengoTODA/spotbugs-gradle-plugin-v2/issues/15#issuecomment-572515786"&gt;my benchmark&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N3Y3rW-U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/rdqfwnnzaz7qek0cv8po.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N3Y3rW-U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/rdqfwnnzaz7qek0cv8po.png" alt="Benchmark Result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It requires Gradle 5.6+ but is actually valuable. You may have a try :)&lt;/p&gt;

</description>
      <category>groovy</category>
      <category>gradle</category>
    </item>
    <item>
      <title>Sign Eclipse plugin by Gradle</title>
      <dc:creator>Kengo TODA</dc:creator>
      <pubDate>Wed, 21 Nov 2018 10:28:15 +0000</pubDate>
      <link>https://dev.to/kengotoda/sign-eclipse-plugin-by-gradle-4md8</link>
      <guid>https://dev.to/kengotoda/sign-eclipse-plugin-by-gradle-4md8</guid>
      <description>&lt;p&gt;When we distribute Eclipse plugin, it is better to sign your .jar files by &lt;code&gt;jarsigner&lt;/code&gt; bundled with JDK. By this process user can install your plugin without warning &lt;a href="https://github.com/spotbugs/spotbugs/issues/779#issue-372330179"&gt;like this&lt;/a&gt;.&lt;br&gt;
In Eclipse wiki we have &lt;a href="https://wiki.eclipse.org/JAR_Signing"&gt;Jar Signing page&lt;/a&gt;, but it explains no detailed method to sign. Here let's see how Gradle can sign your .jar files.&lt;/p&gt;

&lt;p&gt;To sign by &lt;code&gt;jarsigner&lt;/code&gt;, you need &lt;a href="https://en.wikipedia.org/wiki/Keystore"&gt;Java Keystore&lt;/a&gt; file that stores keychain. We can use &lt;code&gt;keytool&lt;/code&gt; to generate self-signed signature, but here we'll use &lt;a href="https://letsencrypt.org/"&gt;Let's Encrypt&lt;/a&gt; to generate non self-signed signature.&lt;/p&gt;

&lt;p&gt;First, follow interaction of Let's Encrypt, then you can generate &lt;code&gt;privkey.pem&lt;/code&gt; and &lt;code&gt;fullchain.pem&lt;/code&gt;. Second, use &lt;code&gt;openssl&lt;/code&gt; command to generate &lt;a href="https://en.wikipedia.org/wiki/PKCS_12"&gt;.p12 file&lt;/a&gt; that is necessary to generate Java Keystore. Here is example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;openssl pkcs12 &lt;span class="nt"&gt;-export&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-in&lt;/span&gt; fullchain.pem &lt;span class="nt"&gt;-inkey&lt;/span&gt; privkey.pem &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-out&lt;/span&gt; your.p12 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-name&lt;/span&gt; eclipse-plugin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Third, generate .jks file by &lt;code&gt;keytool&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;keytool &lt;span class="nt"&gt;-importkeystore&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-srckeystore&lt;/span&gt; your.p12 &lt;span class="nt"&gt;-srcstorepass&lt;/span&gt; &lt;span class="nv"&gt;$SRC_PASS&lt;/span&gt; &lt;span class="nt"&gt;-srcstoretype&lt;/span&gt; PKCS12 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-destkeystore&lt;/span&gt; your.jks &lt;span class="nt"&gt;-deststorepass&lt;/span&gt; &lt;span class="nv"&gt;$DEST_PASS&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We use this .jks file to sign, so remember your &lt;code&gt;$DEST_PASS&lt;/code&gt;. You also need to keep this .jks file secret. If you're using Travis CI, &lt;a href="https://docs.travis-ci.com/user/encrypting-files/"&gt;encrypt-file command&lt;/a&gt; is your friend.&lt;/p&gt;

&lt;p&gt;OK now we have all necessary things, let's config our &lt;code&gt;build.gradle&lt;/code&gt; file.&lt;br&gt;
What you need is a function to sign both &lt;code&gt;plugins&lt;/code&gt; jar file and &lt;code&gt;feature&lt;/code&gt; jar files. Groovy itself doesn't provide feature to sign, so use &lt;a href="https://ant.apache.org/manual/Tasks/signjar.html"&gt;Ant's SignJar task&lt;/a&gt; instead like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="c1"&gt;// sign all .jar file under specified dir&lt;/span&gt;
&lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signJar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;keystorepass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'DEST_PASS'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;keystorepass&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keystorepass&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;'to sign eclipse plugins, set "DEST_PASS" project property'&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;traverse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;type:&lt;/span&gt; &lt;span class="n"&gt;FILES&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;nameFilter:&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="s"&gt;/.*\.jar$/&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;relativePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rootDir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toPath&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;relativize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toPath&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;println&lt;/span&gt; &lt;span class="s2"&gt;"signing ${relativePath}"&lt;/span&gt;
    &lt;span class="n"&gt;ant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signjar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;destDir:&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parentFile&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;jar:&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;alias:&lt;/span&gt; &lt;span class="s1"&gt;'eclipse-plugin'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;keystore:&lt;/span&gt; &lt;span class="s2"&gt;"path/to/your.jks"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;storepass:&lt;/span&gt; &lt;span class="n"&gt;keystorepass&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;tsaurl:&lt;/span&gt; &lt;span class="s1"&gt;'http://timestamp.digicert.com'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;verbose:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Well done! You can simply invoke this function between jar task and &lt;code&gt;artifacts.xml&lt;/code&gt; file generation (because this &lt;code&gt;artifacts.xml&lt;/code&gt; contains md5 hash of .jar files).&lt;/p&gt;

&lt;p&gt;Here is &lt;a href="https://github.com/spotbugs/spotbugs/pull/803"&gt;a PR that introduces jarsigner to SpotBugs build&lt;/a&gt;, you may check it as working solution. It uses Gradle 5.0 RC3, but it should work with Gradle 4 too.&lt;/p&gt;

</description>
      <category>eclipse</category>
      <category>java</category>
      <category>gradle</category>
    </item>
    <item>
      <title>Build stage on Travis CI</title>
      <dc:creator>Kengo TODA</dc:creator>
      <pubDate>Fri, 27 Jul 2018 10:55:48 +0000</pubDate>
      <link>https://dev.to/kengotoda/build-stage-on-travis-ci-3pdk</link>
      <guid>https://dev.to/kengotoda/build-stage-on-travis-ci-3pdk</guid>
      <description>&lt;p&gt;Today I found &lt;a href="https://blog.travis-ci.com/2018-07-18-build-stages-officially-released"&gt;a Travis CI blog post&lt;/a&gt; regarding build stage on Travis CI. Now it goes GA so we all can enjoy this feature.&lt;/p&gt;

&lt;p&gt;Here is &lt;a href="https://github.com/KengoTODA/findbugs-slf4j/pull/118/files"&gt;the my PR to introduce build stage&lt;/a&gt;. In my feeling, it has one good point:&lt;/p&gt;

&lt;h2&gt;
  
  
  No more &lt;code&gt;if&lt;/code&gt; in analysis and deploy part
&lt;/h2&gt;

&lt;p&gt;When I run analysis like &lt;a href="https://sonarcloud.io"&gt;SonarCloud&lt;/a&gt;, it was necessary to limit target JVM &amp;amp; environment variable to make PR page easy to read. For example, here is a &lt;code&gt;.travis.yml&lt;/code&gt; snippet that runs analysis only with specific condition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jdk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;oraclejdk8&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;oraclejdk9&lt;/span&gt;
&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./mvnw org.jacoco:jacoco-maven-plugin:prepare-agent verify -B&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;if [[ $TRAVIS_JDK_VERSION == "oraclejdk8" ]]; then ./mvnw sonar:sonar -B; fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case of build stage, script runs with the first value in &lt;code&gt;env&lt;/code&gt;, &lt;code&gt;jdk&lt;/code&gt; and others by default. So we can remove &lt;code&gt;if&lt;/code&gt; from &lt;code&gt;.travis.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jdk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;oraclejdk8&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;oraclejdk9&lt;/span&gt;
&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./mvnw verify -B&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;analysis&lt;/span&gt;
      &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./mvnw org.jacoco:jacoco-maven-plugin:prepare-agent verify sonar:sonar -B&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One point, is that, each build stage and job doesn't share generated files. So here we need to run &lt;code&gt;verify&lt;/code&gt; phase even in &lt;code&gt;analysis&lt;/code&gt; stage, to generate analysis targets (&lt;code&gt;.class&lt;/code&gt; file in this case).&lt;/p&gt;

&lt;p&gt;This merit works even to &lt;a href="https://docs.travis-ci.com/user/deployment"&gt;deploy&lt;/a&gt; phase. This feature should reduce complexity in our &lt;code&gt;.travis.yml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's all. Enjoy hacking with Travis CI!&lt;/p&gt;

</description>
      <category>travis</category>
      <category>build</category>
      <category>deploy</category>
      <category>ci</category>
    </item>
  </channel>
</rss>
