Skip to content

Commit 52f3cbb

Browse files
authored
Merge pull request #576 from screamerbg/feature_releases
New feature: mbed releases
2 parents 6007f8d + e08f184 commit 52f3cbb

File tree

3 files changed

+164
-24
lines changed

3 files changed

+164
-24
lines changed

README.md

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,24 @@ Use `mbed ls` to list all the libraries imported to your program:
163163

164164
```
165165
$ cd mbed-os-program
166-
$ mbed ls -a
167-
mbed-os-program (mbed-os-program)
168-
`- mbed-os (https://github.com/ARMmbed/mbed-os#89962277c207)
166+
$ mbed ls
167+
mbed-os-program (no revision)
168+
`- mbed-os (#182bbd51bc8d, tags: latest, mbed-os-5.6.5)
169+
```
170+
171+
Use `mbed releases` to list all releases in a program or library:
172+
173+
```
174+
$ cd mbed-os
175+
$ mbed releases
176+
mbed-os (#182bbd51bc8d, tags: latest, mbed-os-5.6.5)
177+
...
178+
* mbed-os-5.6.0
179+
* mbed-os-5.6.1
180+
* mbed-os-5.6.2
181+
* mbed-os-5.6.3
182+
* mbed-os-5.6.4
183+
* mbed-os-5.6.5 <- current
169184
```
170185

171186
<span class="notes">**Note**: If you want to start from an existing folder in your workspace, you can use `mbed new .`, which initializes an Mbed program, as well as a new Git or Mercurial repository in that folder. </span>
@@ -686,11 +701,11 @@ To push the changes in your local tree upstream, run `mbed publish`. `mbed publi
686701
Let's assume that the list of dependencies of your program (obtained by running `mbed ls`) looks like this:
687702

688703
```
689-
my-mbed-os-example (a5ac4bf2e468)
690-
|- mbed-os (5fea6e69ec1a)
691-
`- my-libs (e39199afa2da)
692-
|- my-libs/iot-client (571cfef17dd0)
693-
`- my-libs/test-framework (cd18b5a50df4)
704+
my-mbed-os-example (#a5ac4bf2e468)
705+
|- mbed-os (#182bbd51bc8d, tags: latest, mbed-os-5.6.5)
706+
`- my-libs (#e39199afa2da)
707+
|- my-libs/iot-client (#571cfef17dd0)
708+
`- my-libs/test-framework (#cd18b5a50df4)
694709
```
695710

696711
Let's assume that you make changes to `iot-client`. `mbed publish` detects the change on the leaf `iot-client` dependency and asks you to commit it. Then `mbed publish` detects that `my-libs` depends on `iot-client`, updates the `my-libs` dependency on `iot-client` to its latest version by updating the `iot-client.lib` file and asks you to commit it. This propagates up to `my-libs` and finally to your program, `my-mbed-os-example`.
@@ -741,6 +756,44 @@ The update command fails if there are changes in your program or library that `m
741756

742757
### Updating to an upstream version
743758

759+
Before updating a program or a library, it's good to know the names of the stable releases, usually marked with a tag using a common format, such as `1.2`, `v1.0.1`, `r5.6`, `mbed-os-5.6` and so on.
760+
761+
You can find stable release versions of a program or a library using the `mbed releases` command:
762+
763+
```
764+
$ cd mbed-os
765+
$ mbed releases
766+
mbed-os (#182bbd51bc8d, tags: latest, mbed-os-5.6.5)
767+
...
768+
* mbed-os-5.6.0
769+
* mbed-os-5.6.1
770+
* mbed-os-5.6.2
771+
* mbed-os-5.6.3
772+
* mbed-os-5.6.4
773+
* mbed-os-5.6.5 <- current
774+
```
775+
776+
You can also recursively list stable releases for your program and libraries using the `-r` switch, for example `mbed releases -r`.
777+
778+
Lastly, you can list unstable releases, such as release candidates, alphas and betas by using the `-u` switch.
779+
780+
```
781+
$ cd mbed-client
782+
$ mbed releases -u
783+
mbed-client (#31e5ce203cc0, tags: v3.0.0)
784+
* mbed-os-5.0-rc1
785+
* mbed-os-5.0-rc2
786+
* r0.5-rc4
787+
...
788+
* v2.2.0
789+
* v2.2.1
790+
* v3.0.0 <- current
791+
```
792+
793+
You can use the `-a` switch to print release and revision hash pairs.
794+
795+
Mbed CLI recognizes stable release if the tags are in standard versioning format, such as `MAJOR[.MINOR][.PATCH][.BUILD]`, and optionally prefixed with either `v`, `r` or `mbed-os`. Unstable releases can be suffixed with any letter/number/hyphen/dot combination.
796+
744797
#### Updating a program
745798

746799
To update your program to another upstream version, go to the root folder of the program, and run:
@@ -751,6 +804,7 @@ $ mbed update [branch|tag|revision]
751804

752805
This fetches new revisions from the remote repository, updating the program to the specified branch, tag or revision. If you don't specify any of these, then `mbed update` updates to the latest revision of the current branch. `mbed update` performs this series of actions recursively against all dependencies in the program tree.
753806

807+
754808
#### Updating a library
755809

756810
You can change the working directory to a library folder and use `mbed update` to update that library and its dependencies to a different revision than the one referenced in the parent program or library. This allows you to experiment with different versions of libraries/dependencies in the program tree without having to change the parent program or library.
@@ -769,11 +823,11 @@ There are two main scenarios when updating:
769823

770824
* Update with local uncommitted changes: *dirty* update.
771825

772-
Run `mbed update [branch|revision|tag_name]`. You might have to commit or stash your changes if the source control tool (Git or Mercurial) throws an error that the update will overwrite local changes.
826+
Run `mbed update [branch|tag|revision]`. You might have to commit or stash your changes if the source control tool (Git or Mercurial) throws an error that the update will overwrite local changes.
773827

774828
* Discard local uncommitted changes: *clean* update.
775829

776-
Run `mbed update [branch|revision|tag_name] --clean`
830+
Run `mbed update [branch|tag|revision] --clean`
777831

778832
Specifying a branch to `mbed update` will only check out that branch and won't automatically merge or fast-forward to the remote/upstream branch. You can run `mbed update` to merge (fast-forward) your local branch with the latest remote branch. On Git, you can do `git pull`.
779833

circle.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@ test:
77
- mbed config -G protocol ssh
88
- cd .tests && mbed new new-test
99
- cd .tests/new-test && mbed ls
10+
- cd .tests/new-test && mbed releases -r
1011
- cd .tests/new-test && mbed compile --source=. --source=mbed-os/TESTS/integration/basic -j 0
1112
- cd .tests/new-test && mbed test --compile -n mbed-os-tests-integration-basic -j 0
1213
- cd .tests && mbed import https://developer.mbed.org/teams/Morpheus/code/mbed-Client-Morpheus-hg hg-test
14+
- cd .tests/hg-test && mbed ls
15+
- cd .tests/hg-test && mbed releases -r
1316
- cd .tests/hg-test && mbed update b02527cafcde8612ff051fea57e9975aca598807 --clean
1417
- cd .tests/hg-test && mbed update --clean
1518
- cd .tests/hg-test && mbed compile -j 0
1619
- cd .tests && mbed import https://developer.mbed.org/users/samux/code/USBSerial_HelloWorld bld-test
20+
- cd .tests/bld-test && mbed ls
21+
- cd .tests/bld-test && mbed releases -r
1722
- cd .tests/bld-test/mbed && mbed update 85 --clean
1823
- cd .tests/bld-test && mbed update --clean
1924
- cd .tests/bld-test && mbed compile -m LPC1768 -j 0

mbed/mbed.py

Lines changed: 95 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@
114114
# mbed sdk builds url
115115
regex_build_url = r'^(https?://([\w\-\.]*mbed\.(co\.uk|org|com))/(users|teams)/([\w\-]{1,32})/(repos|code)/([\w\-]+))/builds/?([\w\-]{6,40}|tip)?/?$'
116116

117+
# match official release tags
118+
regex_rels_official = r'^(release|rel|mbed-os|[rv]+)?[.-]?\d+(\.\d+)*$'
119+
# match rc/beta/alpha release tags
120+
regex_rels_all = r'^(release|rel|mbed-os|[rv]+)?[.-]?\d+(\.\d+)*([a-z0-9.-]+)?$'
121+
117122
# base url for all mbed related repos (used as sort of index)
118123
mbed_base_url = 'https://github.com/ARMmbed'
119124
# default mbed OS url
@@ -373,6 +378,9 @@ def getrev():
373378
def getbranch():
374379
return "default"
375380

381+
def gettags(rev=None):
382+
return []
383+
376384

377385
# pylint: disable=no-self-argument, no-method-argument, no-member, no-self-use, unused-argument
378386
@scm('hg')
@@ -516,6 +524,15 @@ def getrev():
516524
def getbranch():
517525
return pquery([hg_cmd, 'branch']).strip() or ""
518526

527+
def gettags(rev=None):
528+
tags = []
529+
refs = pquery([hg_cmd, 'tags']).strip().splitlines() or []
530+
for ref in refs:
531+
m = re.match(r'^(.+?)\s+(\d+)\:([a-f0-9]+)$', ref)
532+
if m and (not rev or m.group(1).startswith(rev)):
533+
tags.append(m.group(1) if rev else [m.group(3), m.group(1)])
534+
return tags
535+
519536
def remoteid(url, rev=None):
520537
return pquery([hg_cmd, 'id', '--id', url] + (['-r', rev] if rev else [])).strip() or ""
521538

@@ -661,7 +678,7 @@ def checkout(rev, clean=False):
661678
return
662679
info("Checkout \"%s\" in %s" % (rev, os.path.basename(os.getcwd())))
663680
branch = None
664-
refs = Git.getrefs(rev)
681+
refs = Git.getbranches(rev)
665682
for ref in refs: # re-associate with a local or remote branch (rev is the same)
666683
m = re.match(r'^(.*?)\/(.*?)$', ref)
667684
if m and m.group(2) != "HEAD": # matches origin/<branch> and isn't HEAD ref
@@ -778,17 +795,39 @@ def getbranch(rev='HEAD'):
778795
branch = "master"
779796
return branch if branch != "HEAD" else ""
780797

781-
# Finds refs (local or remote branches). Will match rev if specified
782-
def getrefs(rev=None, ret_rev=False):
798+
# Get all refs
799+
def getrefs():
800+
try:
801+
return pquery([git_cmd, 'show-ref', '--dereference']).strip().splitlines()
802+
except ProcessException:
803+
return []
804+
805+
# Finds branches (local or remote). Will match rev if specified
806+
def getbranches(rev=None, ret_rev=False):
783807
result = []
784-
lines = pquery([git_cmd, 'show-ref']).strip().splitlines()
785-
for line in lines:
786-
m = re.match(r'^(.+)\s+(.+)$', line)
808+
refs = Git.getrefs()
809+
for ref in refs:
810+
m = re.match(r'^(.+)\s+refs\/(heads|remotes)\/(.+)$', ref)
787811
if m and (not rev or m.group(1).startswith(rev)):
788-
if re.match(r'refs\/(heads|remotes)\/', m.group(2)): # exclude tags
789-
result.append(m.group(1) if ret_rev else re.sub(r'refs\/(heads|remotes)\/', '', m.group(2)))
812+
result.append(m.group(1) if ret_rev else m.group(3))
790813
return result
791814

815+
# Finds tags. Will match rev if specified
816+
def gettags(rev=None):
817+
tags = []
818+
refs = Git.getrefs()
819+
for ref in refs:
820+
m = re.match(r'^(.+)\s+refs\/tags\/(.+)$', ref)
821+
if m and (not rev or m.group(1).startswith(rev)):
822+
t = m.group(2)
823+
if re.match(r'^(.+)\^\{\}$', t): # detect tag "pointer"
824+
t = re.sub(r'\^\{\}$', '', t) # remove "pointer" chars, e.g. some-tag^{}
825+
for tag in tags:
826+
if tag[1] == t:
827+
tags.remove(tag)
828+
tags.append(t if rev else [m.group(1), t])
829+
return tags
830+
792831
# Finds branches a rev belongs to
793832
def revbranches(rev):
794833
branches = []
@@ -2061,7 +2100,7 @@ def update(rev=None, clean=False, clean_files=False, clean_deps=False, ignore=Fa
20612100

20622101
# Synch command
20632102
@subcommand('sync',
2064-
help='Synchronize library references',
2103+
help='Synchronize library references\n\n',
20652104
description=(
20662105
"Synchronizes all library and dependency references (.lib files) in the\n"
20672106
"current program or library.\n"
@@ -2129,21 +2168,63 @@ def sync(recursive=True, keep_refs=False, top=True):
21292168
"View the dependency tree of the current program or library."))
21302169
def list_(detailed=False, prefix='', p_path=None, ignore=False):
21312170
repo = Repo.fromrepo()
2171+
revtags = repo.scm.gettags(repo.rev) if repo.rev else []
2172+
revstr = ('#' + repo.rev[:12] + (', tags: ' + ', '.join(revtags[0:2]) if len(revtags) else '')) if repo.rev else ''
21322173

2133-
print "%s (%s)" % (prefix + (relpath(p_path, repo.path) if p_path else repo.name), ((repo.url+('#'+str(repo.rev)[:12] if repo.rev else '') if detailed else str(repo.rev)[:12]) or 'no revision'))
2174+
print "%s (%s)" % (prefix + (relpath(p_path, repo.path) if p_path else repo.name), ((repo.url + ('#' + str(repo.rev)[:12] if repo.rev else '') if detailed else revstr) or 'no revision'))
21342175

21352176
for i, lib in enumerate(sorted(repo.libs, key=lambda l: l.path)):
2136-
if prefix:
2137-
nprefix = prefix[:-3] + ('| ' if prefix[-3] == '|' else ' ')
2138-
else:
2139-
nprefix = ''
2177+
nprefix = (prefix[:-3] + ('| ' if prefix[-3] == '|' else ' ')) if prefix else ''
21402178
nprefix += '|- ' if i < len(repo.libs)-1 else '`- '
21412179

21422180
if lib.check_repo(ignore):
21432181
with cd(lib.path):
21442182
list_(detailed, nprefix, repo.path, ignore=ignore)
21452183

21462184

2185+
# Command release for cross-SCM release tags of repositories
2186+
@subcommand('releases',
2187+
dict(name=['-a', '--all'], dest='detailed', action='store_true', help='Show revision hashes'),
2188+
dict(name=['-u', '--unstable'], dest='unstable', action='store_true', help='Show unstable releases well, e.g. release candidates, alphas, betas, etc'),
2189+
dict(name=['-r', '--recursive'], action='store_true', help='Show release tags for all libraries and sub-libraries as well'),
2190+
help='Show release tags',
2191+
description=(
2192+
"Show release tags for the current program or library."))
2193+
def releases_(detailed=False, unstable=False, recursive=False, prefix='', p_path=None):
2194+
repo = Repo.fromrepo()
2195+
tags = repo.scm.gettags()
2196+
revtags = repo.scm.gettags(repo.rev) if repo.rev else [] # associated tags with current commit
2197+
revstr = ('#' + repo.rev[:12] + (', tags: ' + ', '.join(revtags[0:2]) if len(revtags) else '')) if repo.rev else ''
2198+
regex_rels = regex_rels_all if unstable else regex_rels_official
2199+
2200+
# Generate list of tags
2201+
rels = []
2202+
for tag in tags:
2203+
if re.match(regex_rels, tag[1]):
2204+
rels.append(tag[1] + " %s%s" % ('#' + tag[0] if detailed else "", " <- current" if tag[1] in revtags else ""))
2205+
2206+
# Print header
2207+
print "%s (%s)" % (prefix + (relpath(p_path, repo.path) if p_path else repo.name), ((repo.url + ('#' + str(repo.rev)[:12] if repo.rev else '') if detailed else revstr) or 'no revision'))
2208+
2209+
# Print list of tags
2210+
rprefix = (prefix[:-3] + ('| ' if prefix[-3] == '|' else ' ')) if recursive and prefix else ''
2211+
rprefix += '| ' if recursive and len(repo.libs) > 1 else ' '
2212+
if len(rels):
2213+
for rel in rels:
2214+
print rprefix + '* ' + rel
2215+
else:
2216+
print rprefix + 'No release tags detected'
2217+
2218+
if recursive:
2219+
for i, lib in enumerate(sorted(repo.libs, key=lambda l: l.path)):
2220+
nprefix = (prefix[:-3] + ('| ' if prefix[-3] == '|' else ' ')) if prefix else ''
2221+
nprefix += '|- ' if i < len(repo.libs)-1 else '`- '
2222+
2223+
if lib.check_repo():
2224+
with cd(lib.path):
2225+
releases_(detailed, unstable, recursive, nprefix, repo.path)
2226+
2227+
21472228
# Command status for cross-SCM status of repositories
21482229
@subcommand('status',
21492230
dict(name=['-I', '--ignore'], action='store_true', help='Ignore errors related to missing libraries.'),

0 commit comments

Comments
 (0)