Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

create Go CLI to automate plugin releases #230

Merged
merged 5 commits into from Nov 28, 2022
Merged

Conversation

pkwarren
Copy link
Member

@pkwarren pkwarren commented Nov 23, 2022

Create a Go CLI (cmd/release/main.go) which automates the creation of plugin releases. A release consists of the following:

  • plugin-releases.json - Contains metadata about all plugins (including name, version, digests).
  • plugin-releases.json.minisign - Minisign signature of plugin-releases.json.
  • owner-name-version.zip - One or more zip files containing a buf.plugin.yaml and image.tar (created with docker save).

The CLI is configured to run once daily. It detects any changes since the latest release and will upload only the added/changed plugins.

There are two supported options to the CLI:

  • -minisign-private-key <key>: Path to minisign private key. If omitted, the plugin-releases.json file will not be signed.
  • -dry-run: If true, the release will be created locally and saved to a temporary directory on disk, but no changes will be made to GitHub.

Create a Go CLI (cmd/release/main.go) which automates the creation of
plugin releases. A release consists of the following:

* plugin-releases.json - Contains metadata about all plugins (including
  name, version, digests).
* plugin-releases.json.minisign - Minisign signature of
  plugin-releases.json.
* <owner>-<name>-<version>.zip - One or more zip files containing a
  buf.plugin.yaml and image.tar (created with docker save).

The CLI is configured to run once daily. It detects any changes since
the latest release and will upload only the added/changed plugins.

There are two supported options to the CLI:

* `-minisign-private-key <key>`: Path to minisign private key. If
  omitted, the plugin-releases.json file will not be signed.
* `-dry-run`: If true, the release will be created locally and saved to
  a temporary directory on disk, but no changes will be made to GitHub.
@@ -60,6 +60,7 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
if: github.repository == 'bufbuild/plugins'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made steps of existing workflows that can't be run on forks behind a conditional.

- if: ${{ env.dockerhub_username != '' }}
name: Login to Docker Hub
- name: Login to Docker Hub
if: github.repository == 'bufbuild/plugins'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of testing if we can get a secret, only run on our original repo.

@@ -1,6 +1,7 @@
.build/
.idea/
.vscode/
minisign.*
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created a key locally for testing and didn't want to check it in (not any security risk - this was just for E2E testing).

@@ -81,7 +81,9 @@ func Walk(dir string, f func(plugin *Plugin)) error {
return err
}
for _, p := range sorted {
f(p)
if err := f(p); err != nil {
return err
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a fair amount of logic while walking plugins and wanted to fail fast, so updated this method signature to allow it.

const (
githubOwner = "bufbuild"
// This is separate from githubOwner for testing releases (can point at personal fork)
githubReleaseOwner = githubOwner // "pkwarren"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was useful to test things against my fork.

}
root := flag.Args()[0]
if err := run(root, minisignPrivateKey, dryRun); err != nil {
log.Fatalln(err.Error())
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only fatal logger - this ensures we clean things up (like temporary directories) on error.

return fmt.Errorf("failed to create temporary directory: %w", err)
}
log.Printf("created tmp dir: %s", tmpDir)
if !dryRun {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With --dry-run, it is useful to inspect what would be uploaded.

MINISIGN_PRIVATE_KEY: ${{ secrets.MINISIGN_PRIVATE_KEY }}
MINISIGN_PRIVATE_KEY_PASSWORD: ${{ secrets.MINISIGN_PRIVATE_KEY_PASSWORD }}
run: |
echo "${MINISIGN_PRIVATE_KEY}" > minisign.key
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

case:
rules:
json: snake
yaml: snake
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this for you @mfridman.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appreciate it. Although may be overkill as I'm sure this will result in a lot of //nolint: because of the upstream JSON blobs we're interfacing with, esp. in fetcher.

Copy link
Member

@mfridman mfridman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all looks sane, I do like the release portion of it where one can quickly get the current state of the world.

Let's sync up about the .zip files and consider making the docker images public. I did a POC in core to see what uploading a .zip file would look like, and it's not great to be honest. For as long as plugins are docker images, we should lean on the docker ecosystem as much as possible.

case:
rules:
json: snake
yaml: snake
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appreciate it. Although may be overkill as I'm sure this will result in a lot of //nolint: because of the upstream JSON blobs we're interfacing with, esp. in fetcher.

@pkwarren pkwarren merged commit abb474f into main Nov 28, 2022
@pkwarren pkwarren deleted the pkw/BSR-902-github-release branch November 28, 2022 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants