Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion .github/workflows/retention-plan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ jobs:
app-id: ${{ secrets.PROBE_APP_ID }}
private-key: ${{ secrets.PROBE_APP_PRIVATE_KEY }}
owner: TykTechnologies
repositories: artifact-retention-plans
repositories: artifact-retention-plans,tyk-docs
permission-contents: write
permission-pull-requests: write

- name: Checkout gromit
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
Expand Down Expand Up @@ -131,6 +132,32 @@ jobs:
echo "Nothing was deleted by this workflow."
} >> "$GITHUB_STEP_SUMMARY"

# No PR is opened when the table is unchanged
- name: Checkout tyk-docs
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
repository: TykTechnologies/tyk-docs
token: ${{ steps.app-token.outputs.token }}
path: tyk-docs
persist-credentials: false

- name: Render retired-versions snippet
run: go run . pkgs retirement --plan plan.json > tyk-docs/snippets/retired-versions.mdx

- name: PR the snippet to tyk-docs
uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5
with:
token: ${{ steps.app-token.outputs.token }}
path: tyk-docs
branch: gromit/retired-versions
delete-branch: true
commit-message: 'Update retired versions table'
title: 'Update retired versions table'
body: |
Regenerated from the latest [retention plan](https://github.com/TykTechnologies/artifact-retention-plans/commit/${{ steps.commit.outputs.sha }}) by [this run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).

The table in `snippets/retired-versions.mdx` reflects the retention cutoffs the pruning run will enforce.

- name: Slack notice
if: steps.diff.outputs.new_count != '0'
uses: slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95 # v3.0.1
Expand Down
32 changes: 32 additions & 0 deletions cmd/pkgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ var pkgsCmd = &cobra.Command{

You can perform maintenance using this command tree.`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
// retirement works offline, from a plan file
if cmd.Name() == "retirement" {
return
}
pcToken := os.Getenv("PACKAGECLOUD_TOKEN")
if pcToken == "" {
log.Fatal().Msg("Working with packagecloud.io requires PACKAGECLOUD_TOKEN")
Expand Down Expand Up @@ -215,10 +219,35 @@ plan must not proceed to deletion.`,
},
}

var retirementSubCmd = &cobra.Command{
Use: "retirement",
Short: "Render the public retired-versions table from a plan",
Long: `Reads a plan (the JSON from 'pkgs plan --json') and emits the
retired-versions snippet published on the tyk.io retention policy
page. Only track-driven repos appear in the table.

Rendering from the committed plan rather than recomputing keeps the
published table identical to what the pruning run will enforce.`,
RunE: func(cmd *cobra.Command, args []string) error {
planFile, _ := cmd.Flags().GetString("plan")
data, err := os.ReadFile(planFile)
if err != nil {
return err
}
var plans []pkgs.Plan
if err := json.Unmarshal(data, &plans); err != nil {
return fmt.Errorf("parsing %s: %w", planFile, err)
}
fmt.Fprint(cmd.OutOrStdout(), pkgs.RenderRetiredVersions(plans))
return nil
},
}

func init() {
pkgsCmd.AddCommand(cleanSubCmd)
pkgsCmd.AddCommand(planSubCmd)
pkgsCmd.AddCommand(mirrorSubCmd)
pkgsCmd.AddCommand(retirementSubCmd)
rootCmd.AddCommand(pkgsCmd)

pkgsCmd.PersistentFlags().String("owner", "tyk", "PackageCloud repo owner")
Expand All @@ -238,4 +267,7 @@ func init() {
mirrorSubCmd.Flags().String("bucket", "tyk-artifact-archive", "S3 bucket to archive to")
mirrorSubCmd.Flags().Bool("verify", false, "Read every archived object back and check its hash")
mirrorSubCmd.Flags().Int("concurrency", 3, "Repos to mirror in parallel")

retirementSubCmd.Flags().String("plan", "", "Plan file from 'pkgs plan --json'")
retirementSubCmd.MarkFlagRequired("plan")
}
3 changes: 3 additions & 0 deletions config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,8 @@ pkgs:
# versioncutoff below still drives `pkgs clean`
track: gateway
editions: [ce, ee]
# display name on the tyk.io retirement page
name: Tyk Gateway
# exceptions are those versions that should not be deleted from
# packagecloud. These don't have to be semver.
exceptions:
Expand All @@ -886,6 +888,7 @@ pkgs:
notbackup: false
track: gateway
editions: [ce, ee]
name: Tyk Dashboard
exceptions:
- v2.6.2
- v2.9.3
Expand Down
2 changes: 2 additions & 0 deletions pkgs/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ type pkgConfig struct {
// window, longest wins.
Track string
Editions []string
// Name is the display name on the tyk.io retirement page
Name string
}

// CleanConfig is the consolidated options that can be passed to the Clean method
Expand Down
4 changes: 4 additions & 0 deletions pkgs/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ type Plan struct {
NotBefore time.Time `json:"not_before"`
Track string `json:"track,omitempty"`
Editions []string `json:"editions,omitempty"`
// Product is the display name from the pkgs config, carried in
// the plan so downstream renderers need no config access
Product string `json:"product,omitempty"`
// Anchor is the series the retention window counts down from,
// Cutoff the oldest retained series, Series every minor series
// with released packages
Expand Down Expand Up @@ -90,6 +93,7 @@ func BuildPlan(repoName string, cfg pkgConfig, tracks Tracks, items []pc.Package
NotBefore: now.Add(grace),
Track: cfg.Track,
Editions: cfg.Editions,
Product: cfg.Name,
PrunedSeries: make(map[string]int),
Protected: make(map[string]int),
}
Expand Down
2 changes: 2 additions & 0 deletions pkgs/plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func TestBuildPlanTrackDriven(t *testing.T) {
Track: "gateway",
Editions: []string{"ce", "ee"},
Exceptions: []string{"v3.0.9"},
Name: "Tyk Test",
}
items := []pc.PackageDetail{
pkg("2.8.3", 8*365*24*time.Hour), // below cutoff: pruned
Expand All @@ -51,6 +52,7 @@ func TestBuildPlanTrackDriven(t *testing.T) {
// (5.3, 5.2, 3.0), so the cutoff is v3.0
plan, err := BuildPlan("tyk-test", cfg, testTracks, items, planNow, planGrace)
require.NoError(t, err)
assert.Equal(t, "Tyk Test", plan.Product)

// the plan carries its own grace-period deadline
assert.Equal(t, planNow.AddDate(0, 0, 30), plan.NotBefore)
Expand Down
54 changes: 54 additions & 0 deletions pkgs/retire.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package pkgs

import (
"fmt"
"sort"
"strings"

"golang.org/x/mod/semver"
)

// ProductName title-cases a repo name, the fallback for plans that
// predate the product field
func ProductName(repo string) string {
words := strings.Split(repo, "-")
for i, w := range words {
if w == "" {
continue
}
words[i] = strings.ToUpper(w[:1]) + w[1:]
}
return strings.Join(words, " ")
}

// RenderRetiredVersions renders the tyk-docs retirement table from a
// plan. Only track-driven repos appear, so the published table cannot
// disagree with what pruning will do.
func RenderRetiredVersions(plans []Plan) string {
var b strings.Builder
b.WriteString(`{/* This table is generated by gromit from the release tracks
configuration. Do not edit it by hand: changes will be
overwritten by the next sync. */}

| Product | Retained from | Retired below |
|---------|---------------|---------------|
`)
rows := make([]string, 0, len(plans))
for _, p := range plans {
if p.Track == "" || p.Cutoff == "" {
continue
}
series := strings.TrimPrefix(semver.MajorMinor(p.Cutoff), "v")
oldest := strings.TrimPrefix(semver.Canonical(p.Cutoff), "v")
name := p.Product
if name == "" {
name = ProductName(p.Repo)
}
rows = append(rows, fmt.Sprintf("| %s | %s.x | %s |\n", name, series, oldest))
}
sort.Strings(rows)
for _, r := range rows {
b.WriteString(r)
}
return b.String()
}
33 changes: 33 additions & 0 deletions pkgs/retire_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package pkgs

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestRenderRetiredVersions(t *testing.T) {
plans := []Plan{
{Repo: "tyk-gateway", Track: "gateway", Cutoff: "v5.5", Product: "Tyk Gateway"},
// no product: falls back to title-casing the repo name
{Repo: "tyk-dashboard", Track: "gateway", Cutoff: "v5.5"},
// not track-driven, must not appear
{Repo: "tyk-pump", Cutoff: "v1.0.0"},
{Repo: "tyk-identity-broker"},
}
want := `{/* This table is generated by gromit from the release tracks
configuration. Do not edit it by hand: changes will be
overwritten by the next sync. */}

| Product | Retained from | Retired below |
|---------|---------------|---------------|
| Tyk Dashboard | 5.5.x | 5.5.0 |
| Tyk Gateway | 5.5.x | 5.5.0 |
`
assert.Equal(t, want, RenderRetiredVersions(plans))
}

func TestProductName(t *testing.T) {
assert.Equal(t, "Tyk Gateway", ProductName("tyk-gateway"))
assert.Equal(t, "Tyk Sync", ProductName("tyk-sync"))
}
Loading