Skip to content

Commit 3b74e62

Browse files
authored
Adding workflow and resolving markdown linting (#15)
* Adding workflow and resolving markdown linting * Golang linting
1 parent 94c48a7 commit 3b74e62

12 files changed

Lines changed: 274 additions & 78 deletions

File tree

.github/workflows/main.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: PR Checks
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
permissions:
10+
contents: read
11+
pull-requests: read
12+
13+
jobs:
14+
build-and-test:
15+
name: Build and Test
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v4.2.2
20+
21+
- name: Set up Go
22+
uses: actions/setup-go@v5.4.0
23+
with:
24+
go-version-file: 'go.mod'
25+
cache: true
26+
27+
- name: Get dependencies
28+
run: go mod download
29+
30+
- name: Build
31+
run: go build -v .
32+
33+
- name: Run linting
34+
uses: golangci/golangci-lint-action@v7.0.0
35+
with:
36+
version: latest
37+
args: --timeout=5m
38+
39+
markdown:
40+
name: Lint Markdown
41+
runs-on: ubuntu-latest
42+
steps:
43+
- name: Checkout code
44+
uses: actions/checkout@v4.2.2
45+
46+
- name: Setup Node.js
47+
uses: actions/setup-node@v4.4.0
48+
with:
49+
node-version: '16'
50+
51+
- name: Install markdownlint
52+
run: npm install -g markdownlint-cli
53+
54+
- name: Lint Markdown files
55+
run: |
56+
markdownlint '**/*.md' \
57+
--ignore node_modules \
58+
--ignore '**/output/**' \
59+
--config .markdownlint.yaml

.github/workflows/release.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@ on:
55
- "v*"
66
permissions:
77
contents: write
8+
id-token: write
9+
attestations: write
810

911
jobs:
1012
release:
1113
runs-on: ubuntu-latest
1214
steps:
13-
- uses: actions/checkout@v4
14-
- uses: cli/gh-extension-precompile@v2
15+
- uses: actions/checkout@v4.2.2
16+
17+
- uses: cli/gh-extension-precompile@v2.0.0
1518
with:
16-
go_version: "1.23"
19+
generate_attestations: true
20+
go_version_file: go.mod

.markdownlint.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Example markdownlint configuration with all properties set to their default value
2+
3+
# Default state for all rules
4+
default: true
5+
6+
MD013:
7+
# Number of characters
8+
line_length: 100
9+
# Number of characters for headings
10+
heading_line_length: 100
11+
# Number of characters for code blocks
12+
code_block_line_length: 100
13+
# Include code blocks
14+
code_blocks: false
15+
# Include tables
16+
tables: false
17+
# Include headings
18+
headings: true
19+
# Strict length checking
20+
strict: false
21+
# Stern length checking
22+
stern: false
23+
MD033:
24+
# Allowed elements
25+
allowed_elements: [tr, td, code, th, summary, details, table, b]

README.md

Lines changed: 58 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
# gh-seva
22

3-
A GitHub `gh` [CLI](https://cli.github.com/) extension to list and create Secrets and Variables defined at an Organization level and/or Repository level.
3+
[![GitHub Release](https://img.shields.io/github/v/release/katiem0/gh-seva?style=flat&logo=github)](https://github.com/katiem0/gh-seva/releases)
4+
[![PR Checks](https://github.com/katiem0/gh-seva/actions/workflows/main.yml/badge.svg)](https://github.com/katiem0/gh-seva/actions/workflows/main.yml)
5+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6+
[![Go Report Card](https://goreportcard.com/badge/github.com/katiem0/gh-seva)](https://goreportcard.com/report/github.com/katiem0/gh-seva)
7+
[![Go Version](https://img.shields.io/github/go-mod/go-version/katiem0/gh-seva)](https://go.dev/)
8+
9+
A GitHub `gh` [CLI](https://cli.github.com/) extension to list and create Secrets and Variables
10+
defined at an Organization level and/or Repository level.
411

512
## Installation
613

7-
1. Install the `gh` CLI - see the [installation](https://github.com/cli/cli#installation) instructions.
14+
1. Install the `gh` CLI - see the [installation](https://github.com/cli/cli#installation)
15+
instructions.
816

917
2. Install the extension:
18+
1019
```sh
1120
gh extension install katiem0/gh-seva
1221
```
@@ -15,14 +24,16 @@ For more information: [`gh extension install`](https://cli.github.com/manual/gh_
1524

1625
## Usage
1726

18-
This extension supports listing and creating secrets and variables between `GitHub.com` and GitHub Enterprise Server, through the use of `--hostname` and `--source-hostname`.
27+
This extension supports listing and creating secrets and variables between `GitHub.com` and
28+
GitHub Enterprise Server, through the use of `--hostname` and `--source-hostname`.
29+
30+
If you are listing or creating org level secrets or variables, you'll need to ensure you
31+
have logged in with the `admin:org` scope. To do so, run the following command:
1932

20-
If you are listing or creating org level secrets or variables, you'll need to ensure you have logged in with the `admin:org` scope. To do so, run the following command:
2133
```sh
2234
gh auth login -s admin:org
2335
```
2436

25-
2637
```sh
2738
$ gh seva -h
2839
Export and Create secrets and variables for an organization and/or repositories.
@@ -42,7 +53,8 @@ Use "seva [command] --help" for more information about a command.
4253

4354
### Secrets
4455

45-
The `gh seva secrets` command comprises of two subcommands, `export` and `create`, to access and create Organization level and repository level secrets.
56+
The `gh seva secrets` command comprises of two subcommands, `export` and `create`, to access
57+
and create Organization level and repository level secrets.
4658

4759
```sh
4860
$ gh seva secrets -h
@@ -63,15 +75,19 @@ Use "seva secrets [command] --help" for more information about a command.
6375

6476
#### Create Secrets
6577

66-
The `gh seva secrets create` command will create secrets from a `csv` file that contains the following information:
78+
The `gh seva secrets create` command will create secrets from a `csv` file that contains
79+
the following information:
6780

6881
- `SecretLevel`: If the secret was created at the organization or repository level
6982
- `SecretType`: If the secret was created for `Actions`, `Dependabot` or `Codespaces`
7083
- `SecretName`: The name of the secret
71-
- `SecretValue`: The value of the secret that will be [encrypted using the associated `public key`](https://docs.github.com/en/actions/security-guides/encrypted-secrets)
72-
- `SecretAccess`: If an organization level secret, the visibility of the secret (i.e. `all`, `private`, or `scoped`)
73-
- `RepositoryNames`: The name of the repositories that the secret can be accessed from (delimited with `;`)
74-
- `RepositoryIDs`: The `id` of the repositories that the secret can be accessed from (delimited with `;`)
84+
- `SecretValue`: The value of the secret that will be [encrypted using the associated `public key`](https://docs.github.com/en/actions/security-guides/encrypted-secrets)
85+
- `SecretAccess`: If an organization level secret, the visibility of the secret
86+
(i.e. `all`, `private`, or `scoped`)
87+
- `RepositoryNames`: The name of the repositories that the secret can be accessed
88+
from (delimited with `;`)
89+
- `RepositoryIDs`: The `id` of the repositories that the secret can be accessed
90+
from (delimited with `;`)
7591

7692
This extension supports `GitHub.com` and GHES, through the use of `--hostname` and `--token`.
7793

@@ -94,15 +110,21 @@ Global Flags:
94110

95111
#### Export Secrets
96112

97-
The `gh seva secrets export` command exports secrets for the specified `<organization>` or `[repo ..]` list. If `<organization>` is selected, **both organization level and repository level secrets will be exported**. The report will contain secrets produces a `csv` report with the following:
113+
The `gh seva secrets export` command exports secrets for the specified `<organization>`
114+
or `[repo ..]` list. If `<organization>` is selected, **both organization level and repository
115+
level secrets will be exported**. The report will contain secrets produces a `csv` report
116+
with the following:
98117

99118
- `SecretLevel`: If the secret was created at the organization or repository level
100119
- `SecretType`: If the secret was created for `Actions`, `Dependabot` or `Codespaces`
101120
- `SecretName`: The name of the secret
102-
- `SecretValue`: This field **will be blank**, we cannot export secret values.
103-
- `SecretAccess`: If an organization level secret, this is the visibility of the secret (i.e. `all`, `private`, or `scoped`)
104-
- `RepositoryNames`: The name of the repositories that the secret can be accessed from (delimited with `;`)
105-
- `RepositoryIDs`: The `id` of the repositories that the secret can be accessed from (delimited with `;`)
121+
- `SecretValue`: This field **will be blank**, we cannot export secret values.
122+
- `SecretAccess`: If an organization level secret, this is the visibility of the secret
123+
(i.e. `all`, `private`, or `scoped`)
124+
- `RepositoryNames`: The name of the repositories that the secret can be accessed from
125+
(delimited with `;`)
126+
- `RepositoryIDs`: The `id` of the repositories that the secret can be accessed from
127+
(delimited with `;`)
106128

107129
This extension supports `GitHub.com` and GHES, through the use of `--hostname` and `--token`.
108130

@@ -131,10 +153,12 @@ Organization level Actions variables can be created and exported, relying on the
131153
- `VariableLevel`: If the variable was created at the organization or repository level
132154
- `VariableName`: The name of the Actions variable
133155
- `VariableValue`: The value of the Actions variable
134-
- `VariableAccess`: If an organization level variable, this is the visibility of the variable (i.e. `all`, `private`, or `scoped`)
135-
- `RepositoryNames`: The name of the repositories that the variable can be accessed from (delimited with `;`)
136-
- `RepositoryIDs`: The `id` of the repositories that the variable can be accessed from (delimited with `;`)
137-
156+
- `VariableAccess`: If an organization level variable, this is the visibility of the
157+
variable (i.e. `all`, `private`, or `scoped`)
158+
- `RepositoryNames`: The name of the repositories that the variable can be accessed
159+
from (delimited with `;`)
160+
- `RepositoryIDs`: The `id` of the repositories that the variable can be accessed
161+
from (delimited with `;`)
138162

139163
```sh
140164
$ gh seva variables -h
@@ -155,9 +179,11 @@ Use "seva variables [command] --help" for more information about a command.
155179

156180
#### Create Variables
157181

158-
Organization level variables can be created from a `csv` file using `--from-file` following the format outlined in [`gh seva variables`](#variables).
182+
Organization level variables can be created from a `csv` file using `--from-file` following the
183+
format outlined in [`gh seva variables`](#variables).
159184

160-
* If specifying a Source Organization (`--source-organization`) to retrieve variables and create under a new Org, the `--source-token` is required.
185+
- If specifying a Source Organization (`--source-organization`) to retrieve variables and
186+
create under a new Org, the `--source-token` is required.
161187

162188
```sh
163189
$ gh seva variables create -h
@@ -182,14 +208,20 @@ Global Flags:
182208

183209
#### Export Variables
184210

185-
The `gh seva variables export` command exports variables for the specified `<organization>` or `[repo ..]` list. If `<organization>` is selected, **both organization level and repository level variables will be exported**. The report will contain variables produces a `csv` report with the following:
211+
The `gh seva variables export` command exports variables for the specified `<organization>`
212+
or `[repo ..]` list. If `<organization>` is selected, **both organization level and repository
213+
level variables will be exported**. The report will contain variables produces a `csv` report
214+
with the following:
186215

187216
- `VariableLevel`: If the variable was created at the organization or repository level
188217
- `VariableName`: The name of the Actions variable
189218
- `VariableValue`: The value of the Actions variable
190-
- `VariableAccess`: If an organization level variable, this is the visibility of the variable (i.e. `all`, `private`, or `scoped`)
191-
- `RepositoryNames`: The name of the repositories that the variable can be accessed from (delimited with `;`)
192-
- `RepositoryIDs`: The `id` of the repositories that the variable can be accessed from (delimited with `;`)
219+
- `VariableAccess`: If an organization level variable, this is the visibility of the variable
220+
(i.e. `all`, `private`, or `scoped`)
221+
- `RepositoryNames`: The name of the repositories that the variable can be accessed from
222+
(delimited with `;`)
223+
- `RepositoryIDs`: The `id` of the repositories that the variable can be accessed from
224+
(delimited with `;`)
193225

194226
This extension supports `GitHub.com` and GHES, through the use of `--hostname` and `--token`.
195227

cmd/secrets/create/create.go

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,10 @@ func NewCmdCreate() *cobra.Command {
9090
createCmd.PersistentFlags().StringVarP(&cmdFlags.hostname, "hostname", "", "github.com", "GitHub Enterprise Server hostname")
9191
createCmd.Flags().StringVarP(&cmdFlags.fileName, "from-file", "f", "", "Path and Name of CSV file to create secrets from (required)")
9292
createCmd.PersistentFlags().BoolVarP(&cmdFlags.debug, "debug", "d", false, "To debug logging")
93-
createCmd.MarkFlagRequired("from-file")
93+
if err := createCmd.MarkFlagRequired("from-file"); err != nil {
94+
zap.S().Errorf("Error marking from-file flag as required: %v", err)
95+
return nil
96+
}
9497

9598
return &createCmd
9699
}
@@ -104,8 +107,11 @@ func runCmdCreate(owner string, cmdFlags *cmdFlags, g *utils.APIGetter) error {
104107
if err != nil {
105108
zap.S().Errorf("Error arose opening secret csv file")
106109
}
107-
// remember to close the file at the end of the program
108-
defer f.Close()
110+
defer func() {
111+
if err := f.Close(); err != nil {
112+
zap.S().Errorf("Error closing file: %v", err)
113+
}
114+
}()
109115
// read csv values using csv.Reader
110116
csvReader := csv.NewReader(f)
111117
secretData, err = csvReader.ReadAll()
@@ -119,9 +125,11 @@ func runCmdCreate(owner string, cmdFlags *cmdFlags, g *utils.APIGetter) error {
119125
}
120126
zap.S().Debugf("Determining secrets to create")
121127
for _, importSecret := range importSecretList {
122-
if importSecret.Level == "Organization" {
128+
switch importSecret.Level {
129+
case "Organization":
123130
zap.S().Debugf("Gathering Organization level secret %s", importSecret.Name)
124-
if importSecret.Type == "Actions" {
131+
switch importSecret.Type {
132+
case "Actions":
125133
zap.S().Debugf("Encrypting Organization level Actions secret %s", importSecret.Name)
126134
publicKey, err := g.GetOrgActionPublicKey(owner)
127135
if err != nil {
@@ -160,7 +168,7 @@ func runCmdCreate(owner string, cmdFlags *cmdFlags, g *utils.APIGetter) error {
160168
if err != nil {
161169
zap.S().Errorf("Error arose creating Actions secret %s", importSecret.Name)
162170
}
163-
} else if importSecret.Type == "Codespaces" {
171+
case "Codespaces":
164172
zap.S().Debugf("Encrypting Organization level Codespaces secret %s", importSecret.Name)
165173
publicKey, err := g.GetOrgCodespacesPublicKey(owner)
166174
if err != nil {
@@ -197,7 +205,7 @@ func runCmdCreate(owner string, cmdFlags *cmdFlags, g *utils.APIGetter) error {
197205
if err != nil {
198206
zap.S().Errorf("Error arose creating Organization Codespaces secret %s", importSecret.Name)
199207
}
200-
} else if importSecret.Type == "Dependabot" {
208+
case "Dependabot":
201209
zap.S().Debugf("Encrypting Organization level Dependabot secret %s", importSecret.Name)
202210
publicKey, err := g.GetOrgDependabotPublicKey(owner)
203211
if err != nil {
@@ -237,13 +245,14 @@ func runCmdCreate(owner string, cmdFlags *cmdFlags, g *utils.APIGetter) error {
237245
zap.S().Errorf("Error arose creating Organization Dependabot secret %s", importSecret.Name)
238246
}
239247

240-
} else {
248+
default:
241249
zap.S().Errorf("Error arose reading secret from csv file")
242250
}
243-
} else if importSecret.Level == "Repository" {
251+
case "Repository":
244252
repoName := importSecret.RepositoryNames[0]
245253
zap.S().Debugf("Gathering Repository level secret %s", importSecret.Name)
246-
if importSecret.Type == "Actions" {
254+
switch importSecret.Type {
255+
case "Actions":
247256
zap.S().Debugf("Encrypting Repository %s level Actions secret %s", repoName, importSecret.Name)
248257
publicKey, err := g.GetRepoActionPublicKey(owner, repoName)
249258
if err != nil {
@@ -273,7 +282,7 @@ func runCmdCreate(owner string, cmdFlags *cmdFlags, g *utils.APIGetter) error {
273282
if err != nil {
274283
zap.S().Errorf("Error arose creating Repository Actions secret %s", importSecret.Name)
275284
}
276-
} else if importSecret.Type == "Codespaces" {
285+
case "Codespaces":
277286
zap.S().Debugf("Encrypting Repository level Codespaces secret %s", importSecret.Name)
278287
publicKey, err := g.GetRepoCodespacesPublicKey(owner, repoName)
279288
if err != nil {
@@ -302,7 +311,7 @@ func runCmdCreate(owner string, cmdFlags *cmdFlags, g *utils.APIGetter) error {
302311
if err != nil {
303312
zap.S().Errorf("Error arose creating Repository Codespaces secret %s", importSecret.Name)
304313
}
305-
} else if importSecret.Type == "Dependabot" {
314+
case "Dependabot":
306315
zap.S().Debugf("Encrypting Repository level Dependabot secret %s", importSecret.Name)
307316
publicKey, err := g.GetRepoDependabotPublicKey(owner, repoName)
308317
if err != nil {
@@ -331,11 +340,10 @@ func runCmdCreate(owner string, cmdFlags *cmdFlags, g *utils.APIGetter) error {
331340
if err != nil {
332341
zap.S().Errorf("Error arose creating Repository Dependabot secret %s", importSecret.Name)
333342
}
334-
335-
} else {
343+
default:
336344
zap.S().Errorf("Error arose reading secret from csv file")
337345
}
338-
} else {
346+
default:
339347
zap.S().Errorf("Error arose reading in where to create secret %s, check csv file.", importSecret.Name)
340348
}
341349
}

0 commit comments

Comments
 (0)