Repository: intuit/auto (ts)

Issue:
Upload Assets plugin: do not create Canary tag/prerelease when running in base branch
**Describe the bug**

When using the `upload-assets` plugin along with `shipit`, the plugin creates a `canary` tag and a `Canary Assets` pre-release when running on the CI (GitHub Action) in the base branch.

**To Reproduce**

Configure a GitHub action that calls `auto shipit`. Auto is configured to upload the `foo.sh` script as an additional release asset:

Content of `.autorc`:
```json
{
  "plugins": [
    "git-tag",
    ["upload-assets", {"assets": ["./dist/bin/packages/tools/foo.sh"]}]
  ],
  "author": "Auto <auto>",
  "owner": "me",
  "repo": "my-repo",
  "shipit": {
    "prerelease": false,
    "noChangelog": true
  }
}
```

Content of the `release-and-publish` action:

```yml
name: 'Release and Publish'
runs:
  using: "composite"
  steps:
    - name: Release and Publish
      run: |
        if auto label --exists skip-release; then
            echo Found the skip-release label, release will be skipped!
        else
            auto shipit -v
        fi
      shell: bash
```

**Expected behavior**

When using the `upload-assets` plugin with `shipit`, it should not create a canary tag/prerelease when running in the base branch.

- The plugin creates the tag/release in the error branch of the [getCanaryGitHubRelease](https://github.com/intuit/auto/blob/main/plugins/upload-assets/src/index.ts#L237) method

The plugin is generic and doesn't have knowledge that it's being invoked by/from `shipit`, adding an `enableCanary` a property to explicitly disable canaries would resolve the issue:

```json
{
  "plugins": [
    [
      "upload-assets", {
          "assets": ["./dist/bin/packages/tools/foo.sh"],
          "enableCanary": "false"
      }
    ]
  ]
}
```

**Screenshots**

The two images below show that we have the "Canary Asserts" being created/updated every release, it was created by running `auto shipit` from the base branch:

![image](https://user-images.githubusercontent.com/11460109/107522261-84ecd980-6b81-11eb-8e0c-f9bb1189cd7f.png)

![image](https://user-images.githubusercontent.com/11460109/107523845-29bbe680-6b83-11eb-96f3-516b796ac1da.png)

This is how I found out about the Canary tag and asset: when enabling Auto in our repository the `canary` tag got picked up as the Current Version, the build failed because Auto was unable to compute the next version from the "non-semver" `vcanary`. Deleting the tag/release allowed us to fix the release, however we were surprised to see that tag reappear:

![image](https://user-images.githubusercontent.com/11460109/107524207-88816000-6b83-11eb-9145-b8c39c36472a.png)

**Environment information:**

Ran `auto info` in a GitHub Action:

<!-- Please run `npx auto info` and put the results in the section below -->

```txt
Run auto info
  auto info
  shell: /bin/bash -e {0}
  env:
    INTUIT_AUTO_URL: https://github.com/intuit/auto/releases/download/v10.13.3/auto-linux.gz
    GITHUB_TOKEN: ***

Environment Information:

"auto" version: v10.13.2
"git"  version: v2.30.0
"node" version: v12.18.1

Project Information:

✔ Repository:      REDACTED
✔ Author Name:     Auto
✔ Author Email:    auto
✔ Current Version: v4.2.0
✔ Latest Release:  v4.2.0 (​https://github.com/REDACTED/REDACTED/releases/tag/v4.2.0​)

✔ Labels configured on GitHub project 

GitHub Token Information:

✔ Token:            [Token starting with v1.f]
✖ Repo Permission:  none
✖ User:             undefined
✔ API:              undefined (​undefined​)
✖ Enabled Scopes:   undefined
✔ Rate Limit:       996/1000
```

**Additional context**

<!-- Add any other context about the problem here. -->
Keep up the good work!

Pull request:
Don't create "Canary Release Assets" during non-canary builds + Change that releases tag to valid semver
# Release Notes

This release changes the tag used for the "Canary Releases Assets" created by the `upload-assets` plugin to be `0.0.0-canary`.
This new tag is a valid semantic version and can be used with other auto commands.

If you already have a canary release assets releases this change will create another under a different tag.
This mean you'll have an old "Canary Releases Assets" release that never updates, feel free to delete the tag/release or just ignore it if you want the urls to the old assets to still exist.

# What Changed

- When cleaning up the canary asset we were unintentionally creating the canary asset release
- Change the tag the canary assets use to be a valid semver. If no tags in the project exist it will fall back to the canary tag in some cases, and that tag must be valid semver

## Why

closes #1790

Todo:

- [x] Add tests
- [ ] Add docs

## Change Type

Indicate the type of change your pull request is:

- [ ] `documentation`
- [x] `patch`
- [ ] `minor`
- [ ] `major`

<!-- GITHUB_RELEASE PR BODY: canary-assets -->
:baby_chick: Download canary assets:

[auto-linux-canary.1802.22144.gz](https://github.com/intuit/auto/releases/download/v0.0.0-canary/auto-linux-canary.1802.22144.gz)  
[auto-macos-canary.1802.22144.gz](https://github.com/intuit/auto/releases/download/v0.0.0-canary/auto-macos-canary.1802.22144.gz)  
[auto-win.exe-canary.1802.22144.gz](https://github.com/intuit/auto/releases/download/v0.0.0-canary/auto-win.exe-canary.1802.22144.gz)
<!-- GITHUB_RELEASE PR BODY: canary-assets -->

<!-- GITHUB_RELEASE PR BODY: canary-version -->
<details>
  <summary>📦 Published PR as canary version: <code>under canary scope @auto-canary@10.16.3-canary.1802.22144.0</code></summary>
  <br />
  
  :sparkles: Test out this PR locally via:
  
  ```bash
  npm install @auto-canary/bot-list@10.16.3-canary.1802.22144.0
  npm install @auto-canary/auto@10.16.3-canary.1802.22144.0
  npm install @auto-canary/core@10.16.3-canary.1802.22144.0
  npm install @auto-canary/package-json-utils@10.16.3-canary.1802.22144.0
  npm install @auto-canary/all-contributors@10.16.3-canary.1802.22144.0
  npm install @auto-canary/brew@10.16.3-canary.1802.22144.0
  npm install @auto-canary/chrome@10.16.3-canary.1802.22144.0
  npm install @auto-canary/cocoapods@10.16.3-canary.1802.22144.0
  npm install @auto-canary/conventional-commits@10.16.3-canary.1802.22144.0
  npm install @auto-canary/crates@10.16.3-canary.1802.22144.0
  npm install @auto-canary/docker@10.16.3-canary.1802.22144.0
  npm install @auto-canary/exec@10.16.3-canary.1802.22144.0
  npm install @auto-canary/first-time-contributor@10.16.3-canary.1802.22144.0
  npm install @auto-canary/gem@10.16.3-canary.1802.22144.0
  npm install @auto-canary/gh-pages@10.16.3-canary.1802.22144.0
  npm install @auto-canary/git-tag@10.16.3-canary.1802.22144.0
  npm install @auto-canary/gradle@10.16.3-canary.1802.22144.0
  npm install @auto-canary/jira@10.16.3-canary.1802.22144.0
  npm install @auto-canary/magic-zero@10.16.3-canary.1802.22144.0
  npm install @auto-canary/maven@10.16.3-canary.1802.22144.0
  npm install @auto-canary/microsoft-teams@10.16.3-canary.1802.22144.0
  npm install @auto-canary/npm@10.16.3-canary.1802.22144.0
  npm install @auto-canary/omit-commits@10.16.3-canary.1802.22144.0
  npm install @auto-canary/omit-release-notes@10.16.3-canary.1802.22144.0
  npm install @auto-canary/pr-body-labels@10.16.3-canary.1802.22144.0
  npm install @auto-canary/released@10.16.3-canary.1802.22144.0
  npm install @auto-canary/s3@10.16.3-canary.1802.22144.0
  npm install @auto-canary/slack@10.16.3-canary.1802.22144.0
  npm install @auto-canary/twitter@10.16.3-canary.1802.22144.0
  npm install @auto-canary/upload-assets@10.16.3-canary.1802.22144.0
  npm install @auto-canary/vscode@10.16.3-canary.1802.22144.0
  # or 
  yarn add @auto-canary/bot-list@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/auto@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/core@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/package-json-utils@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/all-contributors@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/brew@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/chrome@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/cocoapods@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/conventional-commits@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/crates@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/docker@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/exec@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/first-time-contributor@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/gem@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/gh-pages@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/git-tag@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/gradle@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/jira@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/magic-zero@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/maven@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/microsoft-teams@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/npm@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/omit-commits@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/omit-release-notes@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/pr-body-labels@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/released@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/s3@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/slack@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/twitter@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/upload-assets@10.16.3-canary.1802.22144.0
  yarn add @auto-canary/vscode@10.16.3-canary.1802.22144.0
  ```
</details>
<!-- GITHUB_RELEASE PR BODY: canary-version -->


Patch:
diff --git a/plugins/upload-assets/src/index.ts b/plugins/upload-assets/src/index.ts
index 9683eb5e..e332e39e 100644
--- a/plugins/upload-assets/src/index.ts
+++ b/plugins/upload-assets/src/index.ts
@@ -15,9 +15,11 @@ import link from "terminal-link";
 import * as t from "io-ts";
 
 type AssetResponse = RestEndpointMethodTypes["repos"]["uploadReleaseAsset"]["response"]["data"];
+type GitHubRelease = RestEndpointMethodTypes["repos"]["getReleaseByTag"]["response"]["data"];
 
 const stat = promisify(fs.stat);
 const readFile = promisify(fs.readFile);
+const canaryTag = "0.0.0-canary";
 
 const requiredPluginOptions = t.interface({
   /** Paths to assets to upload */
@@ -80,7 +82,7 @@ export default class UploadAssetsPlugin implements IPlugin {
     auto.hooks.canary.tapPromise(
       this.name,
       async ({ canaryIdentifier, dryRun }) => {
-        const canaryRelease = await this.getCanaryGitHubRelease(auto);
+        const canaryRelease = await this.getCanaryGitHubRelease(auto, true);
 
         auto.logger.log.info(endent`${
           dryRun ? "Would update" : "Updating"
@@ -233,21 +235,30 @@ export default class UploadAssetsPlugin implements IPlugin {
       .reduce((acc, item) => [...acc, ...item], []);
   }
 
+  // prettier-ignore
+  private async getCanaryGitHubRelease(auto: Auto): Promise<GitHubRelease | undefined>
+  // prettier-ignore
+  private async getCanaryGitHubRelease(auto: Auto, create: true): Promise<GitHubRelease>
+  // prettier-ignore
   /** Get the release all the canaries are stored in */
-  private async getCanaryGitHubRelease(auto: Auto) {
+  private async getCanaryGitHubRelease(auto: Auto, create = false): Promise<GitHubRelease | undefined> {
     try {
       const canaryRelease = await auto.git!.github.repos.getReleaseByTag({
         repo: auto.git!.options.repo,
         owner: auto.git!.options.owner,
-        tag: "canary",
+        tag: auto.prefixRelease(canaryTag),
       });
 
       return canaryRelease.data;
     } catch (error) {
+      if (!create) {
+        return;
+      }
+
       const canaryRelease = await auto.git!.github.repos.createRelease({
         repo: auto.git!.options.repo,
         owner: auto.git!.options.owner,
-        tag_name: "canary",
+        tag_name:  auto.prefixRelease(canaryTag),
         name: "Canary Assets",
         prerelease: true,
         body: `This release contains preview assets of Pull Requests.`,
@@ -260,6 +271,11 @@ export default class UploadAssetsPlugin implements IPlugin {
   /** Delete old canary asset */
   private async cleanupCanaryAssets(auto: Auto) {
     const canaryRelease = await this.getCanaryGitHubRelease(auto);
+
+    if (!canaryRelease) {
+      return;
+    }
+
     const canaryReleaseAssets = await auto.git!.github.paginate(
       auto.git!.github.repos.listReleaseAssets,
       {


Test patch:
diff --git a/plugins/upload-assets/__tests__/upload-assets-ci.test.ts b/plugins/upload-assets/__tests__/upload-assets-ci.test.ts
index 18dbb7d6..9ed9685a 100644
--- a/plugins/upload-assets/__tests__/upload-assets-ci.test.ts
+++ b/plugins/upload-assets/__tests__/upload-assets-ci.test.ts
@@ -29,19 +29,18 @@ describe("Upload Assets Plugin", () => {
       path.join(__dirname, "./test-assets/macos"),
     ]);
     const hooks = makeHooks();
-    const uploadReleaseAsset = jest
-      .fn()
-      .mockImplementation(({ name }) =>
-        Promise.resolve({
-          data: { id: 2, name, browser_download_url: `http://${name}` },
-        })
-      );
+    const uploadReleaseAsset = jest.fn().mockImplementation(({ name }) =>
+      Promise.resolve({
+        data: { id: 2, name, browser_download_url: `http://${name}` },
+      })
+    );
     const createRelease = jest.fn().mockResolvedValue({ data: { id: 1 } });
     const addToPrBody = jest.fn();
 
     plugin.apply(({
       hooks,
       logger: dummyLog(),
+      prefixRelease: (v) => v,
       git: {
         options,
         addToPrBody,
diff --git a/plugins/upload-assets/__tests__/upload-assets.test.ts b/plugins/upload-assets/__tests__/upload-assets.test.ts
index 18f3e962..5e6fbbec 100644
--- a/plugins/upload-assets/__tests__/upload-assets.test.ts
+++ b/plugins/upload-assets/__tests__/upload-assets.test.ts
@@ -34,6 +34,7 @@ describe("Upload Assets Plugin", () => {
     plugin.apply(({
       hooks,
       logger: dummyLog(),
+      prefixRelease: (v) => v,
       git: {
         options,
         github: {
@@ -64,6 +65,7 @@ describe("Upload Assets Plugin", () => {
     plugin.apply(({
       hooks,
       logger: dummyLog(),
+      prefixRelease: (v) => v,
       git: {
         options,
         github: {
@@ -93,6 +95,7 @@ describe("Upload Assets Plugin", () => {
         release_id: "123",
       })
     );
+    expect(createRelease).not.toHaveBeenCalled();
   });
 
   test("should upload a single canary asset", async () => {
@@ -110,6 +113,7 @@ describe("Upload Assets Plugin", () => {
     plugin.apply(({
       hooks,
       logger: dummyLog(),
+      prefixRelease: (v) => v,
       git: {
         options,
         github: {
@@ -147,6 +151,7 @@ describe("Upload Assets Plugin", () => {
     plugin.apply(({
       hooks,
       logger: dummyLog(),
+      prefixRelease: (v) => v,
       git: {
         options,
         github: {
@@ -184,6 +189,7 @@ describe("Upload Assets Plugin", () => {
     plugin.apply(({
       hooks,
       logger: dummyLog(),
+      prefixRelease: (v) => v,
       git: {
         options,
         github: {
@@ -196,7 +202,7 @@ describe("Upload Assets Plugin", () => {
     await hooks.canary.promise({
       canaryIdentifier: "canary.123",
       bump: SEMVER.patch,
-      dryRun: true
+      dryRun: true,
     });
 
     expect(uploadReleaseAsset).not.toHaveBeenCalled();
@@ -217,6 +223,7 @@ describe("Upload Assets Plugin", () => {
     plugin.apply(({
       hooks,
       logger: dummyLog(),
+      prefixRelease: (v) => v,
       git: {
         options,
         github: {
@@ -250,6 +257,7 @@ describe("Upload Assets Plugin", () => {
     plugin.apply(({
       hooks,
       logger: dummyLog(),
+      prefixRelease: (v) => v,
       git: {
         options: { ...options, baseUrl: "https://github.my.com/api/v3" },
         github: {
@@ -296,6 +304,7 @@ describe("Upload Assets Plugin", () => {
     plugin.apply(({
       hooks,
       logger: dummyLog(),
+      prefixRelease: (v) => v,
       git: {
         options,
         github: {
@@ -329,6 +338,7 @@ describe("Upload Assets Plugin", () => {
     plugin.apply(({
       hooks,
       logger: dummyLog(),
+      prefixRelease: (v) => v,
       git: {
         options,
         github: {
@@ -372,6 +382,7 @@ describe("Upload Assets Plugin", () => {
     plugin.apply(({
       hooks,
       logger: dummyLog(),
+      prefixRelease: (v) => v,
       git: {
         options,
         github: {
@@ -404,15 +415,16 @@ describe("Upload Assets Plugin", () => {
     const hooks = makeHooks();
     const deleteReleaseAsset = jest.fn();
     const uploadReleaseAsset = jest.fn().mockResolvedValue({});
-    const createRelease = jest.fn().mockResolvedValue({ data: { id: 1 } });
+    const getReleaseByTag = jest.fn().mockResolvedValue({ data: { id: 1 } });
 
     plugin.apply(({
       hooks,
       logger: dummyLog(),
+      prefixRelease: (v) => v,
       git: {
         options,
         github: {
-          repos: { uploadReleaseAsset, createRelease, deleteReleaseAsset },
+          repos: { uploadReleaseAsset, getReleaseByTag, deleteReleaseAsset },
           paginate: jest.fn().mockResolvedValue(new Array(303).fill({})),
         },
       },
@@ -442,15 +454,16 @@ describe("Upload Assets Plugin", () => {
     const hooks = makeHooks();
     const deleteReleaseAsset = jest.fn();
     const uploadReleaseAsset = jest.fn().mockResolvedValue({});
-    const createRelease = jest.fn().mockResolvedValue({ data: { id: 1 } });
+    const getReleaseByTag = jest.fn().mockResolvedValue({ data: { id: 1 } });
 
     plugin.apply(({
       hooks,
       logger: dummyLog(),
+      prefixRelease: (v) => v,
       git: {
         options,
         github: {
-          repos: { uploadReleaseAsset, createRelease, deleteReleaseAsset },
+          repos: { uploadReleaseAsset, getReleaseByTag, deleteReleaseAsset },
           paginate: jest.fn().mockResolvedValue(new Array(300).fill({})),
         },
       },