Skip to content

Commit 5e59a3e

Browse files
authored
git updates for deploys (#72)
* reorg service init, add archive branch, etc * separate deletes in archive, fetch for remake * clean up debug output * poetry lock, add changes, add py3.12 * update copyright date * don't failfast on tests * add more changelog detail
1 parent eb12792 commit 5e59a3e

File tree

10 files changed

+658
-601
lines changed

10 files changed

+658
-601
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
runs-on: ubuntu-latest
99
steps:
1010
- name: Check out repository
11-
uses: actions/checkout@v2
11+
uses: actions/checkout@v4
1212
- name: Install virtualenv from poetry
1313
uses: 20c/workflows/poetry@v1
1414
- name: deploy mkdocs gh-pages site

.github/workflows/tests.yml

+4-5
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,26 @@ jobs:
1111
linting:
1212
runs-on: ubuntu-latest
1313
steps:
14-
- uses: actions/checkout@v2
14+
- uses: actions/checkout@v4
1515
- name: Install virtualenv from poetry
1616
uses: 20c/workflows/poetry@v1
17-
# poetry run pre-commit run --all-files
1817
- name: Run linters
1918
run: |
2019
poetry run black --check .
2120
2221
test:
2322
needs: linting
2423
strategy:
25-
fail-fast: true
24+
fail-fast: false
2625
matrix:
2726
os: [ "ubuntu-latest", "macos-latest" ]
28-
python-version: [ "3.8", "3.9", "3.10", "3.11" ]
27+
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ]
2928
exclude:
3029
- os: "macos-latest"
3130
runs-on: ${{ matrix.os }}
3231
steps:
3332
- name: Check out repository
34-
uses: actions/checkout@v2
33+
uses: actions/checkout@v4
3534
- name: Install virtualenv from poetry
3635
uses: 20c/workflows/poetry@v1
3736
with:

.pre-commit-config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ repos:
2121
hooks:
2222
- id: pyupgrade
2323
name: pyupgrade
24-
entry: poetry run pyupgrade --py37-plus
24+
entry: poetry run pyupgrade --py38-plus
2525
language: python
2626
types: [python]
2727
pass_filenames: true

CHANGELOG.yaml

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
Unreleased:
2-
added: []
3-
fixed: []
4-
changed: []
2+
added:
3+
- configless execution
4+
- new git plugin with support for gitlab, github
5+
- new git with support for ephemeral repos
6+
- archive branch
7+
- py3.12
8+
fixed:
9+
- fetch remote before branch remake
10+
- throw if remotes don't match url (#69)
11+
changed:
12+
- git service init changes
513
deprecated: []
614
removed: []
715
security: []

Ctl/VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.1.0
1+
1.1.0-dev

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Full control of your environment
1414

1515
## License
1616

17-
Copyright 2016-2023 20C, LLC
17+
Copyright 2016-2024 20C, LLC
1818

1919
Licensed under the Apache License, Version 2.0 (the "License");
2020
you may not use this software except in compliance with the License.

poetry.lock

+546-574
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+4-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[tool.poetry]
55
name = "ctl"
66
repository = "https://github.com/20c/ctl"
7-
version = "1.1.0"
7+
version = "1.1.0-dev"
88
description = "Full control of your environment"
99
authors = ["20C <code@20c.com>"]
1010
readme = "README.md"
@@ -18,14 +18,13 @@ classifiers = [
1818
"Programming Language :: Python :: 3.9",
1919
"Programming Language :: Python :: 3.10",
2020
"Programming Language :: Python :: 3.11",
21+
"Programming Language :: Python :: 3.12",
2122
"Topic :: Software Development",
2223
"Topic :: Software Development :: Build Tools",
2324
"Topic :: Software Development :: Documentation",
2425
]
2526

26-
packages = [
27-
{ include = "ctl", from = "src" },
28-
]
27+
packages = [{ include = "ctl", from = "src" }]
2928

3029

3130
[tool.poetry.scripts]
@@ -49,7 +48,7 @@ pydantic = ">=2.3.0"
4948
# testing
5049
coverage = ">=5"
5150
pytest = ">=6"
52-
pytest-cov = "^2.10.1"
51+
pytest-cov = ">=2.10.1"
5352
pytest-filedata = "^0.4.0"
5453
tox = ">=3"
5554
tox-gh-actions = ">=2"

src/ctl/util/git.py

+86-8
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,13 @@ def current_commit(self):
210210
"""
211211
return self.repo.head.commit.hexsha
212212

213+
def get_hash(self, **kwargs):
214+
"""
215+
Returns the current commit hash
216+
pass short=True for short
217+
"""
218+
return self.repo.git.rev_parse("HEAD", **kwargs)
219+
213220
def init_repository(self):
214221
"""
215222
Clones the repository if it does not exist
@@ -219,6 +226,9 @@ def init_repository(self):
219226
if not os.path.exists(self.directory):
220227
os.makedirs(self.directory)
221228

229+
# init services first to setup auth
230+
self.init_services(self.repository_config)
231+
222232
try:
223233
self.repo = git.Repo(self.directory)
224234

@@ -241,8 +251,14 @@ def init_repository(self):
241251
"No url specified and specified directory is not a git repository"
242252
)
243253

254+
env = os.environ.copy()
255+
self.log.debug(f"Cloning repository from {self.url}: {self.directory}")
244256
self.repo = git.Repo.clone_from(
245-
self.url, self.directory, branch=self.default_branch, progress=None
257+
self.url,
258+
self.directory,
259+
branch=self.default_branch,
260+
progress=None,
261+
env=env,
246262
)
247263
self.init_submodules()
248264

@@ -256,8 +272,6 @@ def init_repository(self):
256272

257273
self.load_repository_config(self.repository_config_filename)
258274

259-
self.init_services(self.repository_config)
260-
261275
def init_submodules(self):
262276
"""
263277
Initializes and updates existing submodules
@@ -322,13 +336,29 @@ def init_services(self, config: RepositoryConfig):
322336
"""
323337
Initializes the services for the repository
324338
"""
325-
if config.gitlab_url and not self.services.gitlab:
339+
# why do we have 2 configs?
340+
if config.gitlab_url != self.repository_config.gitlab_url:
341+
raise ValueError("config passed is not repo config")
342+
343+
# argparse seems to be interfering with the GITLAB_URL var
344+
gitlab_url = os.getenv("GITLAB_URL") or config.gitlab_url
345+
gitlab_token = os.getenv("GITLAB_TOKEN") or config.gitlab_token
346+
# update repo config
347+
self.repository_config.gitlab_token = gitlab_token
348+
self.repository_config.gitlab_url = gitlab_url
349+
350+
if gitlab_url and not self.services.gitlab:
326351
# instance_url wants only the scheme and host
327352
# so we need to parse it out of the full url
353+
instance_url = (
354+
urllib.parse.urlparse(gitlab_url).scheme
355+
+ "://"
356+
+ urllib.parse.urlparse(gitlab_url).netloc
357+
)
328358

329359
self.services.gitlab = GitlabService(
330360
token=config.gitlab_token,
331-
instance_url=self.repository_config.gitlab_url,
361+
instance_url=instance_url,
332362
)
333363
if config.github_token and not self.services.github:
334364
self.services.github = GithubService(token=config.github_token)
@@ -367,14 +397,18 @@ def fetch(self, prune: bool = True):
367397
fetch_args.append("--prune")
368398

369399
self.log.info(f"Fetching from {self.origin.name}")
370-
self.repo.git.fetch(*fetch_args)
400+
fetch_info = self.repo.git.fetch(*fetch_args)
401+
self.log.debug(f"Fetch info: {fetch_info}")
402+
return fetch_info
371403

372404
def pull(self):
373405
"""
374406
Pulls the origin repository
375407
"""
376408
self.log.info(f"Pulling from {self.origin.name}")
377-
self.repo.git.pull(self.origin.name, self.branch)
409+
fetch_info = self.repo.git.pull(self.origin.name, self.branch)
410+
self.log.debug(f"Fetch info: {fetch_info}")
411+
return fetch_info
378412

379413
def push(self, force: bool = False):
380414
"""
@@ -486,6 +520,8 @@ def switch_branch(self, branch_name: str, create: bool = True):
486520
"""
487521

488522
self.log.info(f"Switching to branch {branch_name}")
523+
# fetch to make sure we have the latest refs
524+
self.fetch()
489525

490526
try:
491527
branch_exists_locally = self.repo.heads[branch_name]
@@ -619,6 +655,47 @@ def remote_branch_reference(self, branch_name: str):
619655
return ref
620656
return None
621657

658+
def archive_branch(self, new_name: str, branch: str = None):
659+
"""
660+
Rename the remote branch and delete the local
661+
662+
This renames remote and doesn't check out to local
663+
664+
**Arguments**
665+
666+
- branch_name: The new name of the branch
667+
"""
668+
669+
if not branch:
670+
branch = self.branch
671+
672+
if branch == self.default_branch:
673+
raise ValueError(f"Cannot rename default branch {self.default_branch}")
674+
675+
if branch == self.branch:
676+
# cannot rename current branch
677+
self.switch_branch(self.default_branch)
678+
679+
self.log.info(f"Renaming branch {self.branch} to {new_name}")
680+
681+
# this doesn't rename remote
682+
# self.repo.heads[self.branch].rename(new_name)
683+
684+
# Push the archive branch and delete the merge branch both locally and remotely
685+
repo = self.repo
686+
remote_name = self.origin.name
687+
688+
# not sure if pushing the remote ref is actually working
689+
repo.git.push(remote_name, f"{remote_name}/{branch}:refs/heads/{new_name}")
690+
691+
# if old remote branch is still there, delete it
692+
# this can depend on if the merge option to delete branch was checked
693+
if branch in repo.git.branch("-r").split():
694+
repo.git.push(remote_name, "--delete", branch)
695+
696+
# delete local branch if it exists
697+
repo.delete_head(branch, force=True)
698+
622699
def create_change_request(
623700
self,
624701
title: str,
@@ -744,7 +821,7 @@ def create_pull_request(self, title: str):
744821
return self.create_change_request(title)
745822

746823
def merge_change_request(
747-
self, target_branch: str, source_branch: str, squash: bool = False
824+
self, target_branch: str, source_branch: str, squash: bool = True
748825
):
749826
"""
750827
Merge the change request
@@ -770,6 +847,7 @@ def merge_change_request(
770847
- Pull requests: read and write
771848
- Metadata: read
772849
"""
850+
self.log.info(f"Merging change request for branch {source_branch} {squash}")
773851

774852
if not self.service:
775853
raise ValueError("No service configured")

tox.ini

+3-2
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ python =
3535
3.9: py39
3636
3.10: py310
3737
3.11: py311
38+
3.12: py312
3839

3940
[tox]
40-
envlist = py38,py39,py310,py311
41+
envlist = py38,py39,py310,py311,py312
4142
isolated_build = True
4243

4344
[tox:.package]
@@ -50,4 +51,4 @@ basepython = python3
5051
allowlist_externals = poetry
5152
commands =
5253
poetry install -v
53-
poetry run pytest --cov="{toxinidir}/src" --cov-report=term-missing --cov-report=xml tests/
54+
poetry run pytest --cov="{toxinidir}/src" --cov-report=term-missing --cov-report=xml tests/

0 commit comments

Comments
 (0)