Skip to content

Commit 06e0063

Browse files
authored
Merge pull request #35 from kip93/feature/non-tags
Add support for non-tagged publishing
2 parents ffc7426 + 94c9805 commit 06e0063

File tree

2 files changed

+101
-39
lines changed

2 files changed

+101
-39
lines changed

backend/flakestry/api/publish.py

+51-32
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515

1616

1717
class Publish(BaseModel):
18-
version: str
18+
ref: str | None
19+
version: str | None
1920
metadata: dict[str, Any] | None
2021
metadata_errors: str | None
2122
readme: str | None
@@ -46,18 +47,55 @@ def publish(
4647
# content={"message": "Private repositories are not supported, \
4748
# see https://github.com/flakestry/flakestry.dev/issues"})
4849

50+
github_headers = {
51+
"Authorization": f"Bearer {github_token}",
52+
"X-GitHub-Api-Version": "2022-11-28",
53+
"Accept": "application/vnd.github+json",
54+
}
55+
56+
owner_name, repository_name = token.repository.split("/")
57+
if publish.ref:
58+
ref = publish.ref
59+
elif publish.version:
60+
ref = f"refs/tags/{publish.version}"
61+
else:
62+
return JSONResponse(
63+
status_code=status.HTTP_400_BAD_REQUEST,
64+
content={"message": 'Neither "ref" nor "version" were provided'},
65+
)
66+
67+
# Get info on the commit to be published
68+
commit_response = requests.get(
69+
f"https://api.github.com/repos/{owner_name}/{repository_name}/commits/{ref}",
70+
headers=github_headers,
71+
)
72+
commit_response.raise_for_status()
73+
commit_json = commit_response.json()
74+
commit_sha = commit_json["sha"]
75+
commit_date = commit_json["commit"]["committer"]["date"]
76+
77+
# Validate & parse version
78+
datetime = re.sub(r"[^0-9]", "", commit_date)
79+
if publish.version:
80+
given_version = publish.version.format(
81+
datetime=datetime,
82+
date=datetime[:8],
83+
time=datetime[8:],
84+
)
85+
elif publish.ref and publish.ref.startswith("refs/tags/"):
86+
given_version = publish.ref.removeprefix("refs/tags/")
87+
else:
88+
given_version = f"v0.1.{datetime}"
89+
4990
version_regex = r"^v?([0-9]+\.[0-9]+\.?[0-9]*$)"
50-
version = re.search(version_regex, publish.version)
91+
version = re.search(version_regex, given_version)
5192
if not version:
5293
return JSONResponse(
5394
status_code=status.HTTP_400_BAD_REQUEST,
54-
content={
55-
"message": f"{publish.version} doesn't match regex {version_regex}"
56-
},
95+
content={"message": f"{given_version} doesn't match regex {version_regex}"},
5796
)
5897
else:
5998
version = version.groups()[0]
60-
owner_name, repository_name = token.repository.split("/")
6199

62100
# Create owner if it doesn't exist
63101
owner = session.exec(
@@ -81,45 +119,24 @@ def publish(
81119
session.commit()
82120
session.refresh(repo)
83121

84-
# 400 if version already exists
122+
# 409 if version already exists
85123
if session.exec(
86124
select(Release)
87125
.where(Release.version == version)
88126
.where(Release.repo_id == repo.id)
89127
).first():
90128
return JSONResponse(
91-
status_code=status.HTTP_400_BAD_REQUEST,
92-
content={"message": f"Version {publish.version} already exists"},
93-
)
94-
95-
github_headers = {
96-
"Authorization": f"Bearer {github_token}",
97-
"X-GitHub-Api-Version": "2022-11-28",
98-
"Accept": "application/vnd.github+json",
99-
}
100-
ref_response = requests.get(
101-
f"https://api.github.com/repos/{owner_name}/{repository_name}/git/ref/tags/{publish.version}",
102-
headers=github_headers,
103-
)
104-
ref_response.raise_for_status()
105-
commit = ref_response.json()["object"]["sha"]
106-
107-
if ref_response.json()["object"]["type"] == "tag":
108-
# now we get the commit sha
109-
tag_response = requests.get(
110-
f"https://api.github.com/repos/{owner_name}/{repository_name}/git/tags/{commit}",
111-
headers=github_headers,
129+
status_code=status.HTTP_409_CONFLICT,
130+
content={"message": f"Version {version} already exists"},
112131
)
113-
tag_response.raise_for_status()
114-
commit = tag_response.json()["object"]["sha"]
115132

116133
# index README
117134
try:
118135
description = publish.metadata["description"]
119136
except Exception:
120137
description = None
121138

122-
path = f"{owner_name}/{repository_name}/{commit}/{publish.readme}"
139+
path = f"{owner_name}/{repository_name}/{commit_sha}/{publish.readme}"
123140
if publish.readme:
124141
readme_response = requests.get(
125142
f"https://raw.githubusercontent.com/{path}", headers=github_headers
@@ -129,12 +146,13 @@ def publish(
129146
else:
130147
readme = None
131148

149+
# Do release
132150
release = Release(
133151
repo_id=repo.id,
134152
version=version,
135153
readme_filename=publish.readme,
136154
readme=readme,
137-
commit=commit,
155+
commit=commit_sha,
138156
description=description,
139157
meta_data=publish.metadata,
140158
meta_data_errors=publish.metadata_errors,
@@ -145,6 +163,7 @@ def publish(
145163
session.commit()
146164
session.refresh(release)
147165

166+
# Index release
148167
document = {
149168
"description": description,
150169
"readme": readme,

frontend/src/Pages/Publish.elm

+50-7
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,33 @@ page =
1515
[ Flakestry.Layout.viewNav
1616
, main_ []
1717
[ div
18-
[ class "container px-4 max-w-5xl" ]
18+
[ class "container px-4 py-24 max-w-5xl" ]
1919
[ h1
20-
[ class "py-24 text-4xl font-semibold md:text-center"
21-
]
20+
[ class "text-4xl font-semibold md:text-center" ]
21+
[ text "Publish your Flake" ]
22+
, p
23+
[ class "mt-6 text-l text-slate-600" ]
24+
[ text """
25+
Currently it's possible to publish flakes via GitHub actions.
26+
Here're a few examples on how to make use of it to release your very own flakes.
27+
""" ]
28+
, h2
29+
[ class "max-w-3xl flex items-center pt-12 text-2xl text-slate-900 font-semibold py-4" ]
2230
[ text "Publish your Flake for each tag" ]
2331
, File.defaultOptions
2432
|> File.fileName ".github/workflows/publish.yaml"
2533
|> File.language "yaml"
26-
|> File.contents publishFlakeYaml
27-
|> File.setCopyableContents (Just publishFlakeYaml)
34+
|> File.contents publishTaggedFlakeYaml
35+
|> File.setCopyableContents (Just publishTaggedFlakeYaml)
36+
|> File.view
37+
, h2
38+
[ class "max-w-3xl flex items-center pt-12 text-2xl text-slate-900 font-semibold py-4" ]
39+
[ text "Publish your Flake for each push to the default branch" ]
40+
, File.defaultOptions
41+
|> File.fileName ".github/workflows/publish.yaml"
42+
|> File.language "yaml"
43+
|> File.contents publishRollingFlakeYaml
44+
|> File.setCopyableContents (Just publishRollingFlakeYaml)
2845
|> File.view
2946
]
3047
]
@@ -33,8 +50,8 @@ page =
3350
}
3451

3552

36-
publishFlakeYaml : String
37-
publishFlakeYaml =
53+
publishTaggedFlakeYaml : String
54+
publishTaggedFlakeYaml =
3855
"""name: "Publish a flake to flakestry"
3956
on:
4057
push:
@@ -58,3 +75,29 @@ jobs:
5875
with:
5976
version: "${{ inputs.tag || github.ref_name }}"
6077
"""
78+
79+
80+
publishRollingFlakeYaml : String
81+
publishRollingFlakeYaml =
82+
"""name: "Publish a flake to flakestry"
83+
on:
84+
push:
85+
branches:
86+
- main
87+
workflow_dispatch:
88+
inputs:
89+
ref:
90+
description: "The existing reference to publish"
91+
type: "string"
92+
required: true
93+
jobs:
94+
publish-flake:
95+
runs-on: ubuntu-latest
96+
permissions:
97+
id-token: "write"
98+
contents: "read"
99+
steps:
100+
- uses: flakestry/flakestry-publish@main
101+
with:
102+
ref: "${{ inputs.ref || github.ref }}"
103+
"""

0 commit comments

Comments
 (0)