cmd/relworker: add relworker command

This adds a basic relworker command. relworker subscribes to the relui
queue, and prints messages. Eventually, it will be responsible for
executing the release workflows.

For golang/go#40279

Change-Id: I6a2fd228e20b7074daa05df56470a8c95c1a8462
Reviewed-on: https://go-review.googlesource.com/c/build/+/275236
Trust: Alexander Rakoczy <alex@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Carlos Amedee <carlos@golang.org>
diff --git a/cmd/relworker/README.md b/cmd/relworker/README.md
new file mode 100644
index 0000000..47c41a6
--- /dev/null
+++ b/cmd/relworker/README.md
@@ -0,0 +1,12 @@
+# golang.org/x/build/cmd/relui
+
+```
+               ▀▀█                         █
+  ▄ ▄▄   ▄▄▄     █   ▄     ▄  ▄▄▄    ▄ ▄▄  █   ▄   ▄▄▄    ▄ ▄▄
+  █▀  ▀ █▀  █    █   ▀▄ ▄ ▄▀ █▀ ▀█   █▀  ▀ █ ▄▀   █▀  █   █▀  ▀
+  █     █▀▀▀▀    █    █▄█▄█  █   █   █     █▀█    █▀▀▀▀   █
+  █     ▀█▄▄▀    ▀▄▄   █ █   ▀█▄█▀   █     █  ▀▄  ▀█▄▄▀   █
+
+```
+
+relworker is a worker process for running tasks from relui.
diff --git a/cmd/relworker/main.go b/cmd/relworker/main.go
new file mode 100644
index 0000000..6c024a4
--- /dev/null
+++ b/cmd/relworker/main.go
@@ -0,0 +1,54 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// relworker is a worker process for managing the release process of Go.
+package main
+
+import (
+	"context"
+	"flag"
+	"log"
+	"os"
+	"time"
+
+	"cloud.google.com/go/pubsub"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+)
+
+var (
+	projectID = flag.String("project-id", os.Getenv("PUBSUB_PROJECT_ID"), "Pubsub project ID for communicating with relui. Uses PUBSUB_PROJECT_ID by default.")
+	topicID   = flag.String("topic-id", "relui-development", "Pubsub topic ID for communicating with relui.")
+)
+
+func main() {
+	flag.Parse()
+	ctx := context.Background()
+
+	sub := getSubscription(ctx, *projectID, *topicID, "relworker")
+	log.Fatal(sub.Receive(ctx, func(ctx context.Context, msg *pubsub.Message) {
+		log.Println(string(msg.Data))
+		msg.Ack()
+	}))
+}
+
+// getSubscription creates and returns a pubsub subscription from the project
+// specified in projectId, which is to be used for communicating with relui.
+//
+// It is safe to call if a subscription already exists. A reference to the
+// subscription will be returned.
+func getSubscription(ctx context.Context, projectID, topicID, subscriptionID string) *pubsub.Subscription {
+	client, err := pubsub.NewClient(ctx, projectID)
+	if err != nil {
+		log.Fatalf("pubsub.NewClient(_, %q) = %v, wanted no error", projectID, err)
+	}
+	t := client.Topic(topicID)
+	// TODO(golang.org/issue/40279): determine if these values are appropriate, move to const/config.
+	scfg := pubsub.SubscriptionConfig{Topic: t, AckDeadline: 10 * time.Second, ExpirationPolicy: 24 * time.Hour}
+	_, err = client.CreateSubscription(ctx, subscriptionID, scfg)
+	if err != nil && status.Code(err) != codes.AlreadyExists {
+		log.Fatalf("client.CreateSubscription(_, %q, %v) = _, %q, wanted no error or already exists error", subscriptionID, scfg, err)
+	}
+	return client.Subscription(subscriptionID)
+}