Skip to content

Commit 60d732d

Browse files
Merge pull request #409 from linode/dev
Release 5.34.0
2 parents 295d470 + 61a9dae commit 60d732d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+4670
-318
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: AccTest Command
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
7+
jobs:
8+
acctest-command:
9+
runs-on: ubuntu-latest
10+
if: ${{ github.event.issue.pull_request }}
11+
steps:
12+
- name: Generate App Installation Token
13+
id: generate_token
14+
uses: tibdex/github-app-token@v1
15+
with:
16+
app_id: ${{ secrets.DX_ACCTEST_APP_ID }}
17+
private_key: ${{ secrets.DX_ACCTEST_PRIV_KEY }}
18+
19+
- name: Slash Command Dispatch
20+
uses: peter-evans/slash-command-dispatch@v1
21+
env:
22+
TOKEN: ${{ steps.generate_token.outputs.token }}
23+
with:
24+
token: ${{ env.TOKEN }}
25+
reaction-token: ${{ secrets.GITHUB_TOKEN }}
26+
issue-type: pull-request
27+
commands: acctest
28+
named-args: true
29+
permission: write

.github/workflows/e2e-suite-pr.yml

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
on:
2+
pull_request:
3+
repository_dispatch:
4+
types: [acctest-command]
5+
6+
name: PR E2E Tests
7+
8+
jobs:
9+
# Maintainer has commented /acctest on a pull request
10+
integration-fork:
11+
runs-on: ubuntu-latest
12+
if:
13+
github.event_name == 'repository_dispatch' &&
14+
github.event.client_payload.slash_command.sha != '' &&
15+
github.event.client_payload.pull_request.head.sha == github.event.client_payload.slash_command.sha
16+
17+
steps:
18+
- uses: actions-ecosystem/action-regex-match@v2
19+
id: validate-tests
20+
with:
21+
text: ${{ github.event.client_payload.slash_command.tests }}
22+
regex: '[^a-z0-9-:.\/_]' # Tests validation
23+
flags: gi
24+
25+
# Check out merge commit
26+
- name: Checkout PR
27+
uses: actions/checkout@v2
28+
with:
29+
ref: ${{ github.event.client_payload.slash_command.sha }}
30+
31+
- name: Update system packages
32+
run: sudo apt-get update -y
33+
34+
- name: Install system deps
35+
run: sudo apt-get install -y build-essential
36+
37+
- name: Setup Python
38+
uses: actions/setup-python@v4
39+
with:
40+
python-version: '3.x'
41+
42+
- name: Install Python deps
43+
run: pip install -r requirements.txt -r requirements-dev.txt wheel boto
44+
45+
- name: Install the CLI
46+
run: make install
47+
env:
48+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
49+
50+
- run: make INTEGRATION_TEST_PATH="${{ github.event.client_payload.slash_command.tests }}" testint
51+
if: ${{ steps.validate-tests.outputs.match == '' }}
52+
env:
53+
LINODE_CLI_TOKEN: ${{ secrets.LINODE_TOKEN }}
54+
55+
- uses: actions/github-script@v5
56+
id: update-check-run
57+
if: ${{ always() }}
58+
env:
59+
number: ${{ github.event.client_payload.pull_request.number }}
60+
job: ${{ github.job }}
61+
conclusion: ${{ job.status }}
62+
with:
63+
github-token: ${{ secrets.GITHUB_TOKEN }}
64+
script: |
65+
const { data: pull } = await github.rest.pulls.get({
66+
...context.repo,
67+
pull_number: process.env.number
68+
});
69+
const ref = pull.head.sha;
70+
const { data: checks } = await github.rest.checks.listForRef({
71+
...context.repo,
72+
ref
73+
});
74+
const check = checks.check_runs.filter(c => c.name === process.env.job);
75+
const { data: result } = await github.rest.checks.update({
76+
...context.repo,
77+
check_run_id: check[0].id,
78+
status: 'completed',
79+
conclusion: process.env.conclusion
80+
});
81+
return result;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Remote Release Trigger
2+
on:
3+
repository_dispatch:
4+
types: [ cli-release ]
5+
jobs:
6+
remote-release-trigger:
7+
runs-on: ubuntu-22.04
8+
environment: CLI Automated Release
9+
steps:
10+
- name: Generate App Installation Token
11+
id: generate_token
12+
uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 # pin@v1
13+
with:
14+
app_id: ${{ secrets.CLI_RELEASE_APP_ID }}
15+
private_key: ${{ secrets.CLI_RELEASE_PRIVATE_KEY }}
16+
17+
- name: Checkout
18+
uses: actions/checkout@v3
19+
with:
20+
fetch-depth: 0
21+
22+
- name: Get previous tag
23+
id: previoustag
24+
uses: WyriHaximus/github-action-get-previous-tag@385a2a0b6abf6c2efeb95adfac83d96d6f968e0c # pin@v1
25+
env:
26+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27+
28+
- name: Get the next minor version
29+
id: semvers
30+
uses: WyriHaximus/github-action-next-semvers@d079934efaf011a4cf8912d4637097fe35d32b93 # pin@v1
31+
with:
32+
version: ${{ steps.previoustag.outputs.tag }}
33+
34+
- uses: rickstaa/action-create-tag@84c90e6ba79b47b5147dcb11ff25d6a0e06238ba # pin@v1
35+
with:
36+
tag: ${{ steps.semvers.outputs.v_minor }}
37+
38+
- name: Release
39+
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # pin@v1
40+
with:
41+
token: ${{ steps.generate_token.outputs.token }}
42+
body: Built from Linode OpenAPI spec ${{
43+
github.event.client_payload.spec_version }}
44+
tag_name: ${{ steps.semvers.outputs.v_minor }}

.github/workflows/unit-tests.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ jobs:
2727

2828
- name: Install Package
2929
run: make install
30+
env:
31+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3032

3133
- name: Run the unit test suite
3234
run: make test

Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
# Makefile for more convenient building of the Linode CLI and its baked content
33
#
44

5+
INTEGRATION_TEST_PATH :=
6+
57
SPEC_VERSION ?= latest
68
ifndef SPEC
79
override SPEC = $(shell ./resolve_spec_url ${SPEC_VERSION})
@@ -38,7 +40,7 @@ clean:
3840
rm -f linodecli/data-*
3941
rm -f linode-cli.sh baked_version
4042
rm -f data-*
41-
rm -rf dist
43+
rm -rf dist linode_cli.egg-info build
4244

4345
.PHONY: testunit
4446
testunit: export LINODE_CLI_TEST_MODE = 1
@@ -48,7 +50,7 @@ testunit:
4850

4951
.PHONY: testint
5052
testint:
51-
pytest tests/integration
53+
pytest tests/integration/${INTEGRATION_TEST_PATH}
5254

5355

5456
# Alias for unit; integration tests should be explicit

linodecli/api_request.py

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,11 @@
44

55
import json
66
import sys
7-
from distutils.version import ( # pylint: disable=deprecated-module
8-
LooseVersion,
9-
StrictVersion,
10-
)
117
from sys import version_info
128
from typing import Optional
139

1410
import requests
11+
from packaging import version
1512

1613

1714
def do_request(
@@ -160,26 +157,24 @@ def _attempt_warn_old_version(ctx, result):
160157

161158
try:
162159
# Parse the spec versions from the API and local CLI.
163-
StrictVersion(spec_version)
164-
StrictVersion(ctx.spec_version)
160+
spec_version_parsed = version.parse(spec_version)
161+
current_version_parsed = version.parse(ctx.spec_version)
165162

166163
# Get only the Major/Minor version of the API Spec and CLI Spec,
167164
# ignore patch version differences
168165
spec_major_minor_version = (
169-
spec_version.split(".")[0] + "." + spec_version.split(".")[1]
166+
f"{spec_version_parsed.major}.{spec_version_parsed.minor}"
170167
)
171168
current_major_minor_version = (
172-
ctx.spec_version.split(".")[0]
173-
+ "."
174-
+ ctx.spec_version.split(".")[1]
169+
f"{current_version_parsed.major}.{current_version_parsed.minor}"
175170
)
176171
except ValueError:
177172
# If versions are non-standard like, "DEVELOPMENT" use them and don't complain.
178173
spec_major_minor_version = spec_version
179174
current_major_minor_version = ctx.spec_version
180175

181176
try:
182-
if LooseVersion(spec_major_minor_version) > LooseVersion(
177+
if version.parse(spec_major_minor_version) > version.parse(
183178
current_major_minor_version
184179
):
185180
api_version_higher = True
@@ -209,7 +204,7 @@ def _attempt_warn_old_version(ctx, result):
209204
pypi_version = pypi_response.json()["info"]["version"]
210205

211206
# no need to be fancy; these should always be valid versions
212-
if LooseVersion(pypi_version) > LooseVersion(ctx.version):
207+
if version.parse(pypi_version) > version.parse(ctx.version):
213208
new_version_exists = True
214209
except:
215210
# I know, but if anything happens here the end user should still

linodecli/arg_helpers.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from linodecli import plugins
1515

1616
from .completion import bake_completions
17+
from .helpers import register_args_shared
1718

1819

1920
def register_args(parser):
@@ -102,13 +103,6 @@ def register_args(parser):
102103
help="Suppress default values for arguments. Default values "
103104
"are configured on initial setup or with linode-cli configure",
104105
)
105-
parser.add_argument(
106-
"--as-user",
107-
metavar="USERNAME",
108-
type=str,
109-
help="The username to execute this command as. This user must "
110-
"be configured.",
111-
)
112106
parser.add_argument(
113107
"--suppress-warnings",
114108
action="store_true",
@@ -131,6 +125,8 @@ def register_args(parser):
131125
"--debug", action="store_true", help="Enable verbose HTTP debug output."
132126
)
133127

128+
register_args_shared(parser)
129+
134130
return parser
135131

136132

linodecli/configuration/__init__.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -342,16 +342,19 @@ def configure(
342342
auth_users = []
343343

344344
if is_full_access:
345-
auth_users = [
346-
u["username"]
347-
for u in _do_get_request(
348-
self.base_url,
349-
"/account/users",
350-
exit_on_error=False,
351-
token=token,
352-
)["data"]
353-
if "ssh_keys" in u
354-
]
345+
users = _do_get_request(
346+
self.base_url,
347+
"/account/users",
348+
token=token,
349+
# Allow 401 responses so tokens without
350+
# account perms can be configured
351+
status_validator=lambda status: status == 401,
352+
)
353+
354+
if "data" in users:
355+
auth_users = [
356+
u["username"] for u in users["data"] if "ssh_keys" in u
357+
]
355358

356359
# get the preferred things
357360
config["region"] = _default_thing_input(

linodecli/configuration/auth.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@
2727
"""
2828

2929

30-
def _handle_response_status(response, exit_on_error=None):
30+
def _handle_response_status(
31+
response, exit_on_error=None, status_validator=None
32+
):
33+
if status_validator is not None and status_validator(response.status_code):
34+
return
35+
3136
if 199 < response.status_code < 300:
3237
return
3338

@@ -37,17 +42,30 @@ def _handle_response_status(response, exit_on_error=None):
3742

3843

3944
# TODO: merge config do_request and cli do_request
40-
def _do_get_request(base_url, url, token=None, exit_on_error=True):
45+
def _do_get_request(
46+
base_url, url, token=None, exit_on_error=True, status_validator=None
47+
):
4148
"""
4249
Does helper get requests during configuration
4350
"""
4451
return _do_request(
45-
base_url, requests.get, url, token=token, exit_on_error=exit_on_error
52+
base_url,
53+
requests.get,
54+
url,
55+
token=token,
56+
exit_on_error=exit_on_error,
57+
status_validator=status_validator,
4658
)
4759

4860

4961
def _do_request(
50-
base_url, method, url, token=None, exit_on_error=None, body=None
62+
base_url,
63+
method,
64+
url,
65+
token=None,
66+
exit_on_error=None,
67+
body=None,
68+
status_validator=None,
5169
): # pylint: disable=too-many-arguments
5270
"""
5371
Does helper requests during configuration
@@ -60,7 +78,9 @@ def _do_request(
6078

6179
result = method(base_url + url, headers=headers, json=body)
6280

63-
_handle_response_status(result, exit_on_error=exit_on_error)
81+
_handle_response_status(
82+
result, exit_on_error=exit_on_error, status_validator=status_validator
83+
)
6484

6585
return result.json()
6686

linodecli/helpers.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,23 @@ def filter_markdown_links(text):
5151
result = result.replace(match.group(), f"{match.group('text')} ({url})")
5252

5353
return result
54+
55+
56+
def register_args_shared(parser):
57+
"""
58+
Adds certain arguments to the given ArgumentParser that may be shared across
59+
the CLI and plugins.
60+
This function is wrapped in linodecli.plugins.
61+
62+
NOTE: This file is not located in arg_helpers.py to prevent a cyclic dependency.
63+
"""
64+
65+
parser.add_argument(
66+
"--as-user",
67+
metavar="USERNAME",
68+
type=str,
69+
help="The username to execute this command as. This user must "
70+
"be configured.",
71+
)
72+
73+
return parser

0 commit comments

Comments
 (0)